<commit_before>// ---------------------------------------------------------------------
//
// Copyright (C) 2009 - 2013 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#include <deal.II/base/config.h>

#ifdef DEAL_II_WITH_P4EST

#include <deal.II/lac/vector.h>
#include <deal.II/lac/block_vector.h>
#include <deal.II/lac/parallel_vector.h>
#include <deal.II/lac/parallel_block_vector.h>
#include <deal.II/lac/petsc_vector.h>
#include <deal.II/lac/petsc_block_vector.h>
#include <deal.II/lac/trilinos_vector.h>
#include <deal.II/lac/trilinos_block_vector.h>

#include <deal.II/distributed/solution_transfer.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>

#include <deal.II/base/std_cxx11/bind.h>

DEAL_II_NAMESPACE_OPEN

namespace parallel
{
  namespace distributed
  {

    template<int dim, typename VECTOR, class DH>
    SolutionTransfer<dim, VECTOR, DH>::SolutionTransfer(const DH &dof)
      :
      dof_handler(&dof, typeid(*this).name())
    {}

    template<int dim, typename VECTOR, class DH>
    SolutionTransfer<dim, VECTOR, DH>::~SolutionTransfer()
    {}

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_for_coarsening_and_refinement (const std::vector<const VECTOR *> &all_in)
    {
      input_vectors = all_in;
      register_data_attach( get_data_size() * input_vectors.size() );
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    register_data_attach(const std::size_t size)
    {
      Assert(size > 0, ExcMessage("Please transfer at least one vector!"));

//TODO: casting away constness is bad
      parallel::distributed::Triangulation<dim> *tria
        = (dynamic_cast<parallel::distributed::Triangulation<dim>*>
           (const_cast<dealii::Triangulation<dim>*>
            (&dof_handler->get_tria())));
      Assert (tria != 0, ExcInternalError());

      offset
        = tria->register_data_attach(size,
                                     std_cxx11::bind(&SolutionTransfer<dim, VECTOR, DH>::pack_callback,
                                                     this,
                                                     std_cxx11::_1,
                                                     std_cxx11::_2,
                                                     std_cxx11::_3));

    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_for_coarsening_and_refinement (const VECTOR &in)
    {
      std::vector<const VECTOR *> all_in(1, &in);
      prepare_for_coarsening_and_refinement(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_serialization(const VECTOR &in)
    {
      std::vector<const VECTOR *> all_in(1, &in);
      prepare_serialization(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_serialization(const std::vector<const VECTOR *> &all_in)
    {
      prepare_for_coarsening_and_refinement (all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    deserialize(VECTOR &in)
    {
      std::vector<VECTOR *> all_in(1, &in);
      deserialize(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    deserialize(std::vector<VECTOR *> &all_in)
    {
      register_data_attach( get_data_size() * all_in.size() );

      // this makes interpolate() happy
      input_vectors.resize(all_in.size());

      interpolate(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    interpolate (std::vector<VECTOR *> &all_out)
    {
      Assert(input_vectors.size()==all_out.size(),
             ExcDimensionMismatch(input_vectors.size(), all_out.size()) );

//TODO: casting away constness is bad
      parallel::distributed::Triangulation<dim> *tria
        = (dynamic_cast<parallel::distributed::Triangulation<dim>*>
           (const_cast<dealii::Triangulation<dim>*>
            (&dof_handler->get_tria())));
      Assert (tria != 0, ExcInternalError());

      tria->notify_ready_to_unpack(offset,
                                   std_cxx11::bind(&SolutionTransfer<dim, VECTOR, DH>::unpack_callback,
                                                   this,
                                                   std_cxx11::_1,
                                                   std_cxx11::_2,
                                                   std_cxx11::_3,
                                                   std_cxx11::ref(all_out)));

      for (typename std::vector<VECTOR *>::iterator it=all_out.begin();
           it !=all_out.end();
           ++it)
        (*it)->compress(::dealii::VectorOperation::insert);

      input_vectors.clear();
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    interpolate (VECTOR &out)
    {
      std::vector<VECTOR *> all_out(1, &out);
      interpolate(all_out);
    }

    template<int dim, typename VECTOR, class DH>
    unsigned int
    SolutionTransfer<dim, VECTOR, DH>::
    get_data_size() const
    {
      return sizeof(double)* DoFTools::max_dofs_per_cell(*dof_handler);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    pack_callback(const typename Triangulation<dim,dim>::cell_iterator &cell_,
                  const typename Triangulation<dim,dim>::CellStatus /*status*/,
                  void *data)
    {
      double *data_store = reinterpret_cast<double *>(data);

      typename DH::cell_iterator cell(*cell_, dof_handler);

      const unsigned int dofs_per_cell=cell->get_fe().dofs_per_cell;
      ::dealii::Vector<double> dofvalues(dofs_per_cell);
      for (typename std::vector<const VECTOR *>::iterator it=input_vectors.begin();
           it !=input_vectors.end();
           ++it)
        {
          cell->get_interpolated_dof_values(*(*it), dofvalues);
          std::memcpy(data_store, &dofvalues(0), sizeof(double)*dofs_per_cell);
          data_store += dofs_per_cell;
        }
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    unpack_callback(const typename Triangulation<dim,dim>::cell_iterator &cell_,
                    const typename Triangulation<dim,dim>::CellStatus /*status*/,
                    const void *data,
                    std::vector<VECTOR *> &all_out)
    {
      typename DH::cell_iterator
      cell(*cell_, dof_handler);

      const unsigned int dofs_per_cell=cell->get_fe().dofs_per_cell;
      ::dealii::Vector<double> dofvalues(dofs_per_cell);
      const double *data_store = reinterpret_cast<const double *>(data);

      for (typename std::vector<VECTOR *>::iterator it = all_out.begin();
           it != all_out.end();
           ++it)
        {
          std::memcpy(&dofvalues(0), data_store, sizeof(double)*dofs_per_cell);
          cell->set_dof_values_by_interpolation(dofvalues, *(*it));
          data_store += dofs_per_cell;
        }
    }

  }
}

// explicit instantiations
#include "solution_transfer.inst"

DEAL_II_NAMESPACE_CLOSE

#endif
<commit_msg>improve SolutionTransfer exception<commit_after>// ---------------------------------------------------------------------
//
// Copyright (C) 2009 - 2013 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#include <deal.II/base/config.h>

#ifdef DEAL_II_WITH_P4EST

#include <deal.II/lac/vector.h>
#include <deal.II/lac/block_vector.h>
#include <deal.II/lac/parallel_vector.h>
#include <deal.II/lac/parallel_block_vector.h>
#include <deal.II/lac/petsc_vector.h>
#include <deal.II/lac/petsc_block_vector.h>
#include <deal.II/lac/trilinos_vector.h>
#include <deal.II/lac/trilinos_block_vector.h>

#include <deal.II/distributed/solution_transfer.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>

#include <deal.II/base/std_cxx11/bind.h>

DEAL_II_NAMESPACE_OPEN

namespace parallel
{
  namespace distributed
  {

    template<int dim, typename VECTOR, class DH>
    SolutionTransfer<dim, VECTOR, DH>::SolutionTransfer(const DH &dof)
      :
      dof_handler(&dof, typeid(*this).name())
    {
      parallel::distributed::Triangulation<dim> *tria
        = (dynamic_cast<parallel::distributed::Triangulation<dim>*>
           (const_cast<dealii::Triangulation<dim>*>
            (&dof_handler->get_tria())));
      Assert (tria != 0, ExcMessage("parallel::distributed::SolutionTransfer requires a parallel::distributed::Triangulation object."));
    }

    template<int dim, typename VECTOR, class DH>
    SolutionTransfer<dim, VECTOR, DH>::~SolutionTransfer()
    {}

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_for_coarsening_and_refinement (const std::vector<const VECTOR *> &all_in)
    {
      input_vectors = all_in;
      register_data_attach( get_data_size() * input_vectors.size() );
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    register_data_attach(const std::size_t size)
    {
      Assert(size > 0, ExcMessage("Please transfer at least one vector!"));

//TODO: casting away constness is bad
      parallel::distributed::Triangulation<dim> *tria
        = (dynamic_cast<parallel::distributed::Triangulation<dim>*>
           (const_cast<dealii::Triangulation<dim>*>
            (&dof_handler->get_tria())));
      Assert (tria != 0, ExcInternalError());

      offset
        = tria->register_data_attach(size,
                                     std_cxx11::bind(&SolutionTransfer<dim, VECTOR, DH>::pack_callback,
                                                     this,
                                                     std_cxx11::_1,
                                                     std_cxx11::_2,
                                                     std_cxx11::_3));

    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_for_coarsening_and_refinement (const VECTOR &in)
    {
      std::vector<const VECTOR *> all_in(1, &in);
      prepare_for_coarsening_and_refinement(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_serialization(const VECTOR &in)
    {
      std::vector<const VECTOR *> all_in(1, &in);
      prepare_serialization(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    prepare_serialization(const std::vector<const VECTOR *> &all_in)
    {
      prepare_for_coarsening_and_refinement (all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    deserialize(VECTOR &in)
    {
      std::vector<VECTOR *> all_in(1, &in);
      deserialize(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    deserialize(std::vector<VECTOR *> &all_in)
    {
      register_data_attach( get_data_size() * all_in.size() );

      // this makes interpolate() happy
      input_vectors.resize(all_in.size());

      interpolate(all_in);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    interpolate (std::vector<VECTOR *> &all_out)
    {
      Assert(input_vectors.size()==all_out.size(),
             ExcDimensionMismatch(input_vectors.size(), all_out.size()) );

//TODO: casting away constness is bad
      parallel::distributed::Triangulation<dim> *tria
        = (dynamic_cast<parallel::distributed::Triangulation<dim>*>
           (const_cast<dealii::Triangulation<dim>*>
            (&dof_handler->get_tria())));
      Assert (tria != 0, ExcInternalError());

      tria->notify_ready_to_unpack(offset,
                                   std_cxx11::bind(&SolutionTransfer<dim, VECTOR, DH>::unpack_callback,
                                                   this,
                                                   std_cxx11::_1,
                                                   std_cxx11::_2,
                                                   std_cxx11::_3,
                                                   std_cxx11::ref(all_out)));

      for (typename std::vector<VECTOR *>::iterator it=all_out.begin();
           it !=all_out.end();
           ++it)
        (*it)->compress(::dealii::VectorOperation::insert);

      input_vectors.clear();
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    interpolate (VECTOR &out)
    {
      std::vector<VECTOR *> all_out(1, &out);
      interpolate(all_out);
    }

    template<int dim, typename VECTOR, class DH>
    unsigned int
    SolutionTransfer<dim, VECTOR, DH>::
    get_data_size() const
    {
      return sizeof(double)* DoFTools::max_dofs_per_cell(*dof_handler);
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    pack_callback(const typename Triangulation<dim,dim>::cell_iterator &cell_,
                  const typename Triangulation<dim,dim>::CellStatus /*status*/,
                  void *data)
    {
      double *data_store = reinterpret_cast<double *>(data);

      typename DH::cell_iterator cell(*cell_, dof_handler);

      const unsigned int dofs_per_cell=cell->get_fe().dofs_per_cell;
      ::dealii::Vector<double> dofvalues(dofs_per_cell);
      for (typename std::vector<const VECTOR *>::iterator it=input_vectors.begin();
           it !=input_vectors.end();
           ++it)
        {
          cell->get_interpolated_dof_values(*(*it), dofvalues);
          std::memcpy(data_store, &dofvalues(0), sizeof(double)*dofs_per_cell);
          data_store += dofs_per_cell;
        }
    }

    template<int dim, typename VECTOR, class DH>
    void
    SolutionTransfer<dim, VECTOR, DH>::
    unpack_callback(const typename Triangulation<dim,dim>::cell_iterator &cell_,
                    const typename Triangulation<dim,dim>::CellStatus /*status*/,
                    const void *data,
                    std::vector<VECTOR *> &all_out)
    {
      typename DH::cell_iterator
      cell(*cell_, dof_handler);

      const unsigned int dofs_per_cell=cell->get_fe().dofs_per_cell;
      ::dealii::Vector<double> dofvalues(dofs_per_cell);
      const double *data_store = reinterpret_cast<const double *>(data);

      for (typename std::vector<VECTOR *>::iterator it = all_out.begin();
           it != all_out.end();
           ++it)
        {
          std::memcpy(&dofvalues(0), data_store, sizeof(double)*dofs_per_cell);
          cell->set_dof_values_by_interpolation(dofvalues, *(*it));
          data_store += dofs_per_cell;
        }
    }

  }
}

// explicit instantiations
#include "solution_transfer.inst"

DEAL_II_NAMESPACE_CLOSE

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "Archive.h"
#include <processor/PhysicalMemoryManager.h>
#include <processor/VirtualAddressSpace.h>
#include <utilities/StaticString.h>
#include <panic.h>
#include <Log.h>

Archive::Archive(uint8_t *pPhys, size_t sSize) :
  m_Region("Archive")
{

  if ((reinterpret_cast<physical_uintptr_t>(pPhys) & (PhysicalMemoryManager::getPageSize() - 1)) != 0)
    panic("Archive: Alignment issues");

  if (PhysicalMemoryManager::instance().allocateRegion(m_Region,
                                                       (sSize + PhysicalMemoryManager::getPageSize() - 1) / PhysicalMemoryManager::getPageSize(),
                                                       PhysicalMemoryManager::continuous,
                                                       VirtualAddressSpace::KernelMode,
                                                       reinterpret_cast<physical_uintptr_t>(pPhys))
      == false)
  {
    ERROR("Archive: allocateRegion failed.");
  }
}

Archive::~Archive()
{
  // TODO destroy all pages.
}

size_t Archive::getNumFiles()
{
  size_t i = 0;
  File *pFile = getFirst();
  while (pFile != 0)
  {
    i++;
    pFile = getNext(pFile);
  }
  return i;
}

size_t Archive::getFileSize(size_t n)
{
  File *pFile = get(n);
  NormalStaticString str(pFile->size);
  return str.intValue(8); // Octal
}

char *Archive::getFileName(size_t n)
{
  return get(n)->name;
}

uintptr_t *Archive::getFile(size_t n)
{
  return reinterpret_cast<uintptr_t*>(reinterpret_cast<uintptr_t>(get(n)) + 512);
}

Archive::File *Archive::getFirst()
{
  return reinterpret_cast<File*> (m_Region.virtualAddress());
}

Archive::File *Archive::getNext(File *pFile)
{
  NormalStaticString str(pFile->size);
  size_t size = str.intValue(8); // Octal.
  size_t nBlocks = (size + 511) / 512;
  pFile = adjust_pointer(pFile, 512 * (nBlocks + 1));
  if (pFile->name[0] == '\0')return 0;
  return pFile;
}

Archive::File *Archive::get(size_t n)
{
  File *pFile = getFirst();
  for (size_t i = 0;i < n;i++)
    pFile = getNext(pFile);
  return pFile;
}
<commit_msg>kernel: free used memory in Archive destructor<commit_after>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "Archive.h"
#include <processor/PhysicalMemoryManager.h>
#include <processor/VirtualAddressSpace.h>
#include <utilities/StaticString.h>
#include <panic.h>
#include <Log.h>

Archive::Archive(uint8_t *pPhys, size_t sSize) :
  m_Region("Archive")
{

  if ((reinterpret_cast<physical_uintptr_t>(pPhys) & (PhysicalMemoryManager::getPageSize() - 1)) != 0)
    panic("Archive: Alignment issues");

  if (PhysicalMemoryManager::instance().allocateRegion(m_Region,
                                                       (sSize + PhysicalMemoryManager::getPageSize() - 1) / PhysicalMemoryManager::getPageSize(),
                                                       PhysicalMemoryManager::continuous,
                                                       VirtualAddressSpace::KernelMode,
                                                       reinterpret_cast<physical_uintptr_t>(pPhys))
      == false)
  {
    ERROR("Archive: allocateRegion failed.");
  }
}

Archive::~Archive()
{
  m_Region.free();
}

size_t Archive::getNumFiles()
{
  size_t i = 0;
  File *pFile = getFirst();
  while (pFile != 0)
  {
    i++;
    pFile = getNext(pFile);
  }
  return i;
}

size_t Archive::getFileSize(size_t n)
{
  File *pFile = get(n);
  NormalStaticString str(pFile->size);
  return str.intValue(8); // Octal
}

char *Archive::getFileName(size_t n)
{
  return get(n)->name;
}

uintptr_t *Archive::getFile(size_t n)
{
  return reinterpret_cast<uintptr_t*>(reinterpret_cast<uintptr_t>(get(n)) + 512);
}

Archive::File *Archive::getFirst()
{
  return reinterpret_cast<File*> (m_Region.virtualAddress());
}

Archive::File *Archive::getNext(File *pFile)
{
  NormalStaticString str(pFile->size);
  size_t size = str.intValue(8); // Octal.
  size_t nBlocks = (size + 511) / 512;
  pFile = adjust_pointer(pFile, 512 * (nBlocks + 1));
  if (pFile->name[0] == '\0')return 0;
  return pFile;
}

Archive::File *Archive::get(size_t n)
{
  File *pFile = getFirst();
  for (size_t i = 0;i < n;i++)
    pFile = getNext(pFile);
  return pFile;
}
<|endoftext|>


<commit_before>#include <cmath>
#include <omp.h>
#include "galaxy.h"

void cela::newp1(double dt)
{
    p1 = p + v * dt + a * dt * dt / 2;
}

void cela::flush(double dt)
{
    v += a * dt;
    p = p1;
}

galaxy::galaxy(int n, cela* stars, double step, double G, double t, int
        r, double o, bool aplfx):n(n), dt(step), G(G), t(t), recurdepth(r), omega(o), applyenergyfix(aplfx)
{
    celas = new cela[n];
    int i;
    for (i=0;i<n;i++) {
        celas[i] = stars[i];
    }

    this->calculateEnergy();
    e0 = ek + ep;
}

galaxy::~galaxy()
{
    delete [] celas;
}

void galaxy::setGravity(double gc)
{
    G = gc;
}

void galaxy::setTimeStep(double step)
{
    dt = step;
}

bool galaxy::togglefix()
{
    if (applyenergyfix) {
        applyenergyfix = false;
    } else {
        applyenergyfix = true;
    }

    return applyenergyfix;
}

int galaxy::getCelaNum()
{
    return n;
}

double galaxy::getTime()
{
    return t;
}

int galaxy::getRecDpt()
{
    return recurdepth;
}

double galaxy::getOmega()
{
    return omega;
}

double galaxy::getG()
{
    return G;
}

double galaxy::getStep()
{
    return dt;
}

bool galaxy::appliedfix()
{
    return applyenergyfix;
}

cela* galaxy::output(){
    return celas;
}

void galaxy::setacc(int i)
{
    int j;
    vector r; //vector distance
    double d; //distance
    vector acc(0,0,0);
    vector epi; // unit vector in direction of p[j]-p[i]
    vector dvi,dvj;

    //if (celas[i].c) { //Collided with another cela. acceleration already calculated
    //    return;
    //}

    for (j=0;j<n;j++) { // cela[j]'s gravity on cela[i]
        if (j != i) { //Not myself
            r = celas[j].p - celas[i].p;
            d = r.mag();
            epi = r / d;
            if (d <= (celas[i].r + celas[j].r)) {
                if (!celas[j].c && !celas[i].c) { //Collision with uncollided one
                celas[i].c = true;
                celas[j].c = true;
                dvj = 2 * celas[i].m / (celas[j].m + celas[i].m) * (celas[i].v - celas[j].v) * epi * epi;
                dvi = 2 * celas[j].m / (celas[j].m + celas[i].m) * (celas[j].v - celas[i].v) * epi * epi;
                celas[i].v += dvi;
                celas[j].v += dvj;
                }
                acc += G * celas[j].m * epi / ((celas[i].r + celas[j].r) * (celas[i].r + celas[j].r));
            } else {
                acc += G * celas[j].m * epi / (d * d);
            }
        }
    }

    celas[i].a = acc;
    return;
}

vector galaxy::getacc1(int i)
{
    int j;
    vector r; //vector distance
    double d; //distance
    vector acc(0,0,0);
    vector epi; // unit vector in direction of p[j]-p[i]

    if (celas[i].c) { //Collided in this stepi
        return celas[i].a;
    }

    for (j=0;j<n;j++) { // cela[j]'s gravity on cela[i]
        if (j != i) { //Not myself
            r = celas[j].p1 - celas[i].p1;
            d = r.mag();
            epi = r / d;
            if (d <= (celas[i].r + celas[j].r)) {
                acc += G * celas[j].m * epi / ((celas[i].r + celas[j].r) * (celas[i].r + celas[j].r));
            } else {
                acc += G * celas[j].m * epi / (d * d);
            }
        }
    }

    return acc;
}

void galaxy::calculateEnergy()
{
    int i,j;
    ek = 0;
    ep = 0;
    for (i=0;i<n;i++) {
        ek += celas[i].m * (celas[i].v * celas[i].v) / 2;
        for (j=0;j<i;j++) {
            ep -= G * celas[i].m * celas[j].m / (celas[j].p - celas[i].p).mag();
        }
    }
}

double galaxy::getEnergy()
{
    if (applyenergyfix) {
        return e0;
    }

    this->calculateEnergy();
    return ek + ep;
}

void galaxy::run()
{
    int i,rec;
    double co; // fix coefficient

    for (i=0;i<n;i++) {
        celas[i].c = false;
    }

    for (i=0;i<n;i++) {
        setacc(i);
    }

    for (rec=0;rec<recurdepth;rec++) { //Recursive calculation
        for (i=0;i<n;i++) {
            celas[i].newp1(dt);
        }
        for (i=0;i<n;i++) {
            celas[i].a = celas[i].a * (1 - omega) + getacc1(i) * omega;
        }
    }

    for (i=0;i<n;i++) { //Flush back
        celas[i].newp1(dt);
        celas[i].flush(dt);
    }

    if (applyenergyfix) {  // Fix system energy
        this->calculateEnergy();
        co = sqrt((e0 - ep) / ek);
        for (i=0;i<n;i++) {
            celas[i].v *= co;
        }
    }

    t += dt;
}
<commit_msg>Updated comments<commit_after>#include <cmath>
#include <omp.h>
#include "galaxy.h"

void cela::newp1(double dt)
{
    p1 = p + v * dt + a * dt * dt / 2;
}

void cela::flush(double dt)
{
    v += a * dt;
    p = p1;
}

galaxy::galaxy(int n, cela* stars, double step, double G, double t, int
        r, double o, bool aplfx):n(n), dt(step), G(G), t(t), recurdepth(r), omega(o), applyenergyfix(aplfx)
{
    celas = new cela[n];
    int i;
    for (i=0;i<n;i++) {
        celas[i] = stars[i];
    }

    this->calculateEnergy();
    e0 = ek + ep;
}

galaxy::~galaxy()
{
    delete [] celas;
}

void galaxy::setGravity(double gc)
{
    G = gc;
}

void galaxy::setTimeStep(double step)
{
    dt = step;
}

bool galaxy::togglefix()
{
    if (applyenergyfix) {
        applyenergyfix = false;
    } else {
        applyenergyfix = true;
    }

    return applyenergyfix;
}

int galaxy::getCelaNum()
{
    return n;
}

double galaxy::getTime()
{
    return t;
}

int galaxy::getRecDpt()
{
    return recurdepth;
}

double galaxy::getOmega()
{
    return omega;
}

double galaxy::getG()
{
    return G;
}

double galaxy::getStep()
{
    return dt;
}

bool galaxy::appliedfix()
{
    return applyenergyfix;
}

cela* galaxy::output(){
    return celas;
}

void galaxy::setacc(int i)
{
    int j;
    vector r; //vector distance
    double d; //distance
    vector acc(0,0,0);
    vector epi; // unit vector in direction of p[j]-p[i]
    vector dvi,dvj;

    for (j=0;j<n;j++) { // cela[j]'s gravity on cela[i]
        if (j != i) { //Not myself
            r = celas[j].p - celas[i].p;
            d = r.mag();
            epi = r / d;
            if (d <= (celas[i].r + celas[j].r)) {
                if (!celas[j].c && !celas[i].c) { //Collision with uncollided one
                celas[i].c = true;
                celas[j].c = true;
                dvj = 2 * celas[i].m / (celas[j].m + celas[i].m) * (celas[i].v - celas[j].v) * epi * epi;
                dvi = 2 * celas[j].m / (celas[j].m + celas[i].m) * (celas[j].v - celas[i].v) * epi * epi;
                celas[i].v += dvi;
                celas[j].v += dvj;
                }
                acc += G * celas[j].m * epi / ((celas[i].r + celas[j].r) * (celas[i].r + celas[j].r));
            } else {
                acc += G * celas[j].m * epi / (d * d);
            }
        }
    }

    celas[i].a = acc;
    return;
}

vector galaxy::getacc1(int i)
{
    int j;
    vector r; //vector distance
    double d; //distance
    vector acc(0,0,0);
    vector epi; // unit vector in direction of p[j]-p[i]

    if (celas[i].c) { //Collided in this step
        return celas[i].a;
    }

    for (j=0;j<n;j++) { // cela[j]'s gravity on cela[i]
        if (j != i) { //Not myself
            r = celas[j].p1 - celas[i].p1;
            d = r.mag();
            epi = r / d;
            if (d <= (celas[i].r + celas[j].r)) {
                acc += G * celas[j].m * epi / ((celas[i].r + celas[j].r) * (celas[i].r + celas[j].r));
            } else {
                acc += G * celas[j].m * epi / (d * d);
            }
        }
    }

    return acc;
}

void galaxy::calculateEnergy()
{
    int i,j;
    ek = 0;
    ep = 0;
    for (i=0;i<n;i++) {
        ek += celas[i].m * (celas[i].v * celas[i].v) / 2;
        for (j=0;j<i;j++) {
            ep -= G * celas[i].m * celas[j].m / (celas[j].p - celas[i].p).mag();
        }
    }
}

double galaxy::getEnergy()
{
    if (applyenergyfix) {
        return e0;
    }

    this->calculateEnergy();
    return ek + ep;
}

void galaxy::run()
{
    int i,rec;
    double co; // fix coefficient

    for (i=0;i<n;i++) {
        celas[i].c = false;
    }

    for (i=0;i<n;i++) {
        setacc(i);
    }

    for (rec=0;rec<recurdepth;rec++) { //Recursive calculation
        for (i=0;i<n;i++) {
            celas[i].newp1(dt);
        }
        for (i=0;i<n;i++) {
            celas[i].a = celas[i].a * (1 - omega) + getacc1(i) * omega;
        }
    }

    for (i=0;i<n;i++) { //Flush back
        celas[i].newp1(dt);
        celas[i].flush(dt);
    }

    if (applyenergyfix) {  // Fix system energy
        this->calculateEnergy();
        co = sqrt((e0 - ep) / ek);
        for (i=0;i<n;i++) {
            celas[i].v *= co;
        }
    }

    t += dt;
}
<|endoftext|>


<commit_before>#include "../common/init.h"
#include "util/debug.h"
#include "util/bitmap.h"
#include "util/timedifference.h"
#include <stdlib.h>

#include <math.h>
#include <string>

using std::string;

static void test(Graphics::Bitmap input, string size, int increase){
    Graphics::Bitmap output(input.getWidth() * increase, input.getWidth() * increase);
    for (int i = 1; i < 4; i++){
        TimeDifference timer;
        int max = pow(10, i);
        timer.startTime();
        for (int x = 0; x < max; x++){
            input.StretchHqx(output);
        }
        timer.endTime();
        Global::debug(0) << timer.printAverageTime(size, max) << std::endl;
    }
}

static void run(string path){
    Graphics::Bitmap image(path);

    test(image, "2x", 2);
    test(image, "3x", 3);
    test(image, "4x", 4);
}

int main(int argc, char ** argv){
    Screen::realInit();
    atexit(Screen::realFinish);
    Global::setDebug(0);
    if (argc > 1){
        run(argv[1]);
    } else {
        run("src/test/hqx/test.png");
    }
    return 0;
}
<commit_msg>add xbr performance test. only do filters if the dimensions match exactly<commit_after>#include "../common/init.h"
#include "util/debug.h"
#include "util/bitmap.h"
#include "util/timedifference.h"
#include <stdlib.h>

#include <math.h>
#include <string>

using std::string;

static void testhqx(Graphics::Bitmap input, string size, int increase){
    Graphics::Bitmap output(input.getWidth() * increase, input.getHeight() * increase);
    for (int i = 1; i < 4; i++){
        TimeDifference timer;
        int max = pow(10, i);
        timer.startTime();
        for (int x = 0; x < max; x++){
            input.StretchHqx(output);
        }
        timer.endTime();
        Global::debug(0) << timer.printAverageTime(size, max) << std::endl;
    }
}

static void testxbr(Graphics::Bitmap input, string size, int increase){
    Graphics::Bitmap output(input.getWidth() * increase, input.getHeight() * increase);
    for (int i = 1; i < 4; i++){
        TimeDifference timer;
        int max = pow(10, i);
        timer.startTime();
        for (int x = 0; x < max; x++){
            input.StretchXbr(output);
        }
        timer.endTime();
        Global::debug(0) << timer.printAverageTime(size, max) << std::endl;
    }
}

static void run(string path){
    Graphics::Bitmap image(path);

    testhqx(image, "hq2x", 2);
    testhqx(image, "hq3x", 3);
    testhqx(image, "hq4x", 4);

    testxbr(image, "2xbr", 2);
    testxbr(image, "3xbr", 3);
    testxbr(image, "4xbr", 4);
}

int main(int argc, char ** argv){
    Screen::realInit();
    atexit(Screen::realFinish);
    Global::setDebug(0);
    if (argc > 1){
        run(argv[1]);
    } else {
        run("src/test/hqx/test.png");
    }
    return 0;
}
<|endoftext|>


<commit_before>#include "rice/Array.hpp"
#include "rice/Constructor.hpp"
#include "rice/Object.hpp"

#include "config.h"
#include "generator.h"
#include "question.h"
#include "topic.h"

using namespace ailab;

template<>
question_t from_ruby<question_t>(Rice::Object obj) {
  size_t qid = from_ruby<size_t>(obj.call("question_id"));
  size_t tid = from_ruby<size_t>(obj.call("topic_id"));
  size_t d = from_ruby<size_t>(obj.call("difficulty"));
  std::string t = from_ruby<std::string>(obj.call("text"));

  return question_t(qid, tid, d, t);
}

template<>
Rice::Object to_ruby(question_t const &q) {
  return Rice::Data_Object<question_t>(new question_t(q));
}

template<>
std::vector<question_t> from_ruby<std::vector<question_t>>(Rice::Object obj) {
  Rice::Array arr(obj);

  std::vector<question_t> res;
  res.reserve(arr.size());

  for (Rice::Object o : arr)
    res.push_back(from_ruby<question_t>(o));

  return res;
}

template<>
Rice::Object to_ruby(std::vector<question_t> const &questions) {
  Rice::Array arr;
  for (question_t const &q : questions)
    arr.push(to_ruby(q));
  return arr;
}

template<>
topic_t from_ruby<topic_t>(Rice::Object obj) {
  size_t id = from_ruby<size_t>(obj.call("topic_id"));
  size_t pid = from_ruby<size_t>(obj.call("parent_id"));
  std::string text = from_ruby<std::string>(obj.call("text"));

  return topic_t(id, pid, text);
}

template<>
Rice::Object to_ruby<topic_t>(topic_t const &th) {
  return Rice::Data_Object<topic_t>(new topic_t(th));
}

template<>
std::vector<topic_t> from_ruby<std::vector<topic_t>>(Rice::Object obj) {
  Rice::Array arr(obj);

  std::vector<topic_t> topics;
  topics.reserve(arr.size());

  for (Rice::Object obj : arr)
    topics.push_back(from_ruby<topic_t>(obj));

  return topics;
}

void set_life_time(Rice::Object obj, size_t life_time) {
  Rice::Data_Object<config_t>(obj)->life_time = life_time;
}

size_t get_life_time(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->life_time;
}

void set_mutation_chance(Rice::Object obj, double mutation_chance) {
  Rice::Data_Object<config_t>(obj)->mutation_chance = mutation_chance;
}

double get_mutation_chance(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->mutation_chance;
}

void set_population_size(Rice::Object obj, size_t population_size) {
  Rice::Data_Object<config_t>(obj)->population_size = population_size;
}

size_t get_population_size(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->population_size;
}

void set_variants_count(Rice::Object obj, size_t variants_count) {
  Rice::Data_Object<config_t>(obj)->variants_count = variants_count;
}

size_t get_variants_count(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->variants_count;
}

void set_questions_count(Rice::Object obj, size_t questions_count) {
  Rice::Data_Object<config_t>(obj)->questions_count = questions_count;
}

size_t get_questions_count(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->questions_count;
}

void set_topics(Rice::Object obj, Rice::Array topics) {
  std::vector<size_t> th = from_ruby<std::vector<size_t>>(topics);
  Rice::Data_Object<config_t>(obj)->topics = std::move(th);
}

Rice::Array get_topics(Rice::Object obj) {
  std::vector<size_t> const &topics = Rice::Data_Object<config_t>(obj)->topics;

  Rice::Array arr;
  for (size_t t : topics)
    arr.push(to_ruby<size_t>(t));

  return arr;
}

template<>
config_t from_ruby<config_t>(Rice::Object obj) {
  config_t result;

  result.life_time = from_ruby<size_t>(obj.call("life_time"));
  result.mutation_chance = from_ruby<double>(obj.call("mutation_chance"));
  result.population_size = from_ruby<size_t>(obj.call("population_size"));
  result.variants_count = from_ruby<size_t>(obj.call("variants_count"));
  result.questions_count = from_ruby<size_t>(obj.call("questions_count"));
  result.topics = from_ruby<std::vector<size_t>>(obj.call("topics"));

  return result;
}

template<>
Rice::Object to_ruby<config_t>(config_t const &cnf) {
  return Rice::Data_Object<config_t>(new config_t(cnf));
}

template<>
generator_t from_ruby<generator_t>(Rice::Object obj) {
  config_t config = from_ruby<config_t>(obj.call("config"));
  std::vector<topic_t> topics = from_ruby<std::vector<topic_t>>(obj.call("topics"));
  std::vector<question_t> questions = from_ruby<std::vector<question_t>>(obj.call("questions"));

  return generator_t(std::move(config), std::move(topics), std::move(questions));
}

template<>
Rice::Object to_ruby(generator_t const &t) {
  return Rice::Data_Object<generator_t>(new generator_t(t));
}

template<>
Rice::Object to_ruby<variants_t>(variants_t const &ans) {
  std::vector<std::vector<question_t>> const &questions = ans.get_questions();
  Rice::Array result;
  for (std::vector<question_t> const &arr : questions) {
    Rice::Array buffer;
    for (question_t const &q : arr)
      buffer.push(to_ruby<question_t>(q));
    result.push(buffer);
  }
  return result;
}

extern "C" void Init_tasks_generator() {
  Rice::Module rb_mTasksGenerator = Rice::define_module("TasksGenerator");

  Rice::Data_Type<config_t> rb_cConfig = Rice::define_class_under<config_t>(rb_mTasksGenerator, "Config")
    .define_constructor(Rice::Constructor<config_t, size_t, size_t>(),
      (Rice::Arg("variants_count") = 8, Rice::Arg("questions_count") = 8))
    .define_method("life_time=", &set_life_time)
    .define_method("mutation_chance=", &set_mutation_chance)
    .define_method("population_size=", &set_population_size)
    .define_method("variants_count=", &set_variants_count)
    .define_method("questions_count=", &set_questions_count)
    .define_method("life_time", &get_life_time)
    .define_method("mutation_chance", &get_mutation_chance)
    .define_method("population_size", &get_population_size)
    .define_method("variants_count", &get_variants_count)
    .define_method("questions_count", &get_questions_count)
    .define_method("topics", &get_topics)
    .define_method("topics=", &set_topics);

  Rice::Data_Type<topic_t> rb_ctopic = Rice::define_class_under<topic_t>(rb_mTasksGenerator, "Topic")
    .define_constructor(Rice::Constructor<topic_t, size_t, size_t, std::string>(),
      (Rice::Arg("id"), Rice::Arg("pid"), Rice::Arg("text")))
    .define_method("topic_id", &topic_t::get_topic_id)
    .define_method("parent_id", &topic_t::get_parent_id)
    .define_method("text", &topic_t::get_text);

  Rice::Data_Type<question_t> rb_cQuestion = Rice::define_class_under<question_t>(rb_mTasksGenerator, "Question")
    .define_constructor(Rice::Constructor<question_t, size_t, size_t, size_t, std::string>(),
      (Rice::Arg("id"), Rice::Arg("tid"), Rice::Arg("difficulty"), Rice::Arg("text")))
    .define_method("question_id", &question_t::get_question_id)
    .define_method("topic_id", &question_t::get_topic_id)
    .define_method("difficulty", &question_t::get_difficulty)
    .define_method("text", &question_t::get_text);

  Rice::Data_Type<generator_t> rb_cGenerator = Rice::define_class_under<generator_t>(rb_mTasksGenerator, "Generator")
    .define_constructor(Rice::Constructor<generator_t, config_t, std::vector<topic_t>, std::vector<question_t>>(),
      (Rice::Arg("cnf"), Rice::Arg("topics"), Rice::Arg("questions")))
    .define_method("generate", &generator_t::generate);
}
<commit_msg>added ruby binding for vector<size_t><commit_after>#include "rice/Array.hpp"
#include "rice/Constructor.hpp"
#include "rice/Object.hpp"

#include "config.h"
#include "generator.h"
#include "question.h"
#include "topic.h"

using namespace ailab;

template<>
question_t from_ruby<question_t>(Rice::Object obj) {
  size_t qid = from_ruby<size_t>(obj.call("question_id"));
  size_t tid = from_ruby<size_t>(obj.call("topic_id"));
  size_t d = from_ruby<size_t>(obj.call("difficulty"));
  std::string t = from_ruby<std::string>(obj.call("text"));

  return question_t(qid, tid, d, t);
}

template<>
Rice::Object to_ruby(question_t const &q) {
  return Rice::Data_Object<question_t>(new question_t(q));
}

template<>
std::vector<question_t> from_ruby<std::vector<question_t>>(Rice::Object obj) {
  Rice::Array arr(obj);

  std::vector<question_t> res;
  res.reserve(arr.size());

  for (Rice::Object o : arr)
    res.push_back(from_ruby<question_t>(o));

  return res;
}

template<>
Rice::Object to_ruby(std::vector<question_t> const &questions) {
  Rice::Array arr;
  for (question_t const &q : questions)
    arr.push(to_ruby(q));
  return arr;
}

template<>
topic_t from_ruby<topic_t>(Rice::Object obj) {
  size_t id = from_ruby<size_t>(obj.call("topic_id"));
  size_t pid = from_ruby<size_t>(obj.call("parent_id"));
  std::string text = from_ruby<std::string>(obj.call("text"));

  return topic_t(id, pid, text);
}

template<>
Rice::Object to_ruby<topic_t>(topic_t const &th) {
  return Rice::Data_Object<topic_t>(new topic_t(th));
}

template<>
std::vector<topic_t> from_ruby<std::vector<topic_t>>(Rice::Object obj) {
  Rice::Array arr(obj);

  std::vector<topic_t> topics;
  topics.reserve(arr.size());

  for (Rice::Object obj : arr)
    topics.push_back(from_ruby<topic_t>(obj));

  return topics;
}

template<>
Rice::Object to_ruby<std::vector<size_t>>(std::vector<size_t> const &v) {
  return Rice::Data_Object<std::vector<size_t>>(new std::vector<size_t>(v));
}

template<>
std::vector<size_t> from_ruby<std::vector<size_t>>(Rice::Object obj) {
  Rice::Array arr(obj);

  std::vector<size_t> result;
  result.reserve(arr.size());

  for (Rice::Object obj : arr)
    result.push_back(from_ruby<size_t>(obj));

  return result;
}

void set_life_time(Rice::Object obj, size_t life_time) {
  Rice::Data_Object<config_t>(obj)->life_time = life_time;
}

size_t get_life_time(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->life_time;
}

void set_mutation_chance(Rice::Object obj, double mutation_chance) {
  Rice::Data_Object<config_t>(obj)->mutation_chance = mutation_chance;
}

double get_mutation_chance(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->mutation_chance;
}

void set_population_size(Rice::Object obj, size_t population_size) {
  Rice::Data_Object<config_t>(obj)->population_size = population_size;
}

size_t get_population_size(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->population_size;
}

void set_variants_count(Rice::Object obj, size_t variants_count) {
  Rice::Data_Object<config_t>(obj)->variants_count = variants_count;
}

size_t get_variants_count(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->variants_count;
}

void set_questions_count(Rice::Object obj, size_t questions_count) {
  Rice::Data_Object<config_t>(obj)->questions_count = questions_count;
}

size_t get_questions_count(Rice::Object obj) {
  return Rice::Data_Object<config_t>(obj)->questions_count;
}

void set_topics(Rice::Object obj, Rice::Array topics) {
  std::vector<size_t> th = from_ruby<std::vector<size_t>>(topics);
  Rice::Data_Object<config_t>(obj)->topics = std::move(th);
}

Rice::Array get_topics(Rice::Object obj) {
  std::vector<size_t> const &topics = Rice::Data_Object<config_t>(obj)->topics;

  Rice::Array arr;
  for (size_t t : topics)
    arr.push(to_ruby<size_t>(t));

  return arr;
}

template<>
config_t from_ruby<config_t>(Rice::Object obj) {
  config_t result;

  result.life_time = from_ruby<size_t>(obj.call("life_time"));
  result.mutation_chance = from_ruby<double>(obj.call("mutation_chance"));
  result.population_size = from_ruby<size_t>(obj.call("population_size"));
  result.variants_count = from_ruby<size_t>(obj.call("variants_count"));
  result.questions_count = from_ruby<size_t>(obj.call("questions_count"));
  result.topics = from_ruby<std::vector<size_t>>(obj.call("topics"));

  return result;
}

template<>
Rice::Object to_ruby<config_t>(config_t const &cnf) {
  return Rice::Data_Object<config_t>(new config_t(cnf));
}

template<>
generator_t from_ruby<generator_t>(Rice::Object obj) {
  config_t config = from_ruby<config_t>(obj.call("config"));
  std::vector<topic_t> topics = from_ruby<std::vector<topic_t>>(obj.call("topics"));
  std::vector<question_t> questions = from_ruby<std::vector<question_t>>(obj.call("questions"));

  return generator_t(std::move(config), std::move(topics), std::move(questions));
}

template<>
Rice::Object to_ruby(generator_t const &t) {
  return Rice::Data_Object<generator_t>(new generator_t(t));
}

template<>
Rice::Object to_ruby<variants_t>(variants_t const &ans) {
  std::vector<std::vector<question_t>> const &questions = ans.get_questions();
  Rice::Array result;
  for (std::vector<question_t> const &arr : questions) {
    Rice::Array buffer;
    for (question_t const &q : arr)
      buffer.push(to_ruby<question_t>(q));
    result.push(buffer);
  }
  return result;
}

extern "C" void Init_tasks_generator() {
  Rice::Module rb_mTasksGenerator = Rice::define_module("TasksGenerator");

  Rice::Data_Type<config_t> rb_cConfig = Rice::define_class_under<config_t>(rb_mTasksGenerator, "Config")
    .define_constructor(Rice::Constructor<config_t, size_t, size_t>(),
      (Rice::Arg("variants_count") = 8, Rice::Arg("questions_count") = 8))
    .define_method("life_time=", &set_life_time)
    .define_method("mutation_chance=", &set_mutation_chance)
    .define_method("population_size=", &set_population_size)
    .define_method("variants_count=", &set_variants_count)
    .define_method("questions_count=", &set_questions_count)
    .define_method("life_time", &get_life_time)
    .define_method("mutation_chance", &get_mutation_chance)
    .define_method("population_size", &get_population_size)
    .define_method("variants_count", &get_variants_count)
    .define_method("questions_count", &get_questions_count)
    .define_method("topics", &get_topics)
    .define_method("topics=", &set_topics);

  Rice::Data_Type<topic_t> rb_ctopic = Rice::define_class_under<topic_t>(rb_mTasksGenerator, "Topic")
    .define_constructor(Rice::Constructor<topic_t, size_t, size_t, std::string>(),
      (Rice::Arg("id"), Rice::Arg("pid"), Rice::Arg("text")))
    .define_method("topic_id", &topic_t::get_topic_id)
    .define_method("parent_id", &topic_t::get_parent_id)
    .define_method("text", &topic_t::get_text);

  Rice::Data_Type<question_t> rb_cQuestion = Rice::define_class_under<question_t>(rb_mTasksGenerator, "Question")
    .define_constructor(Rice::Constructor<question_t, size_t, size_t, size_t, std::string>(),
      (Rice::Arg("id"), Rice::Arg("tid"), Rice::Arg("difficulty"), Rice::Arg("text")))
    .define_method("question_id", &question_t::get_question_id)
    .define_method("topic_id", &question_t::get_topic_id)
    .define_method("difficulty", &question_t::get_difficulty)
    .define_method("text", &question_t::get_text);

  Rice::Data_Type<generator_t> rb_cGenerator = Rice::define_class_under<generator_t>(rb_mTasksGenerator, "Generator")
    .define_constructor(Rice::Constructor<generator_t, config_t, std::vector<topic_t>, std::vector<question_t>>(),
      (Rice::Arg("cnf"), Rice::Arg("topics"), Rice::Arg("questions")))
    .define_method("generate", &generator_t::generate);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <vector>
#include "prevector.h"
#include "random.h"

#include "serialize.h"
#include "streams.h"

#include "test/test_dash.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup)

template<unsigned int N, typename T>
class prevector_tester {
    typedef std::vector<T> realtype;
    realtype real_vector;
    realtype real_vector_alt;

    typedef prevector<N, T> pretype;
    pretype pre_vector;
    pretype pre_vector_alt;

    typedef typename pretype::size_type Size;

    void test() {
        const pretype& const_pre_vector = pre_vector;
        BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size());
        BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty());
        for (Size s = 0; s < real_vector.size(); s++) {
             BOOST_CHECK(real_vector[s] == pre_vector[s]);
             BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s]));
             BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s));
             BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
        }
        // BOOST_CHECK(realtype(pre_vector) == real_vector);
        BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
        BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
        size_t pos = 0;
        BOOST_FOREACH(const T& v, pre_vector) {
             BOOST_CHECK(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
             BOOST_CHECK(v == real_vector[--pos]);
        }
        BOOST_FOREACH(const T& v, const_pre_vector) {
             BOOST_CHECK(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
             BOOST_CHECK(v == real_vector[--pos]);
        }
        CDataStream ss1(SER_DISK, 0);
        CDataStream ss2(SER_DISK, 0);
        ss1 << real_vector;
        ss2 << pre_vector;
        BOOST_CHECK_EQUAL(ss1.size(), ss2.size());
        for (Size s = 0; s < ss1.size(); s++) {
            BOOST_CHECK_EQUAL(ss1[s], ss2[s]);
        }
    }

public:
    void resize(Size s) {
        real_vector.resize(s);
        BOOST_CHECK_EQUAL(real_vector.size(), s);
        pre_vector.resize(s);
        BOOST_CHECK_EQUAL(pre_vector.size(), s);
        test();
    }

    void reserve(Size s) {
        real_vector.reserve(s);
        BOOST_CHECK(real_vector.capacity() >= s);
        pre_vector.reserve(s);
        BOOST_CHECK(pre_vector.capacity() >= s);
        test();
    }

    void insert(Size position, const T& value) {
        real_vector.insert(real_vector.begin() + position, value);
        pre_vector.insert(pre_vector.begin() + position, value);
        test();
    }

    void insert(Size position, Size count, const T& value) {
        real_vector.insert(real_vector.begin() + position, count, value);
        pre_vector.insert(pre_vector.begin() + position, count, value);
        test();
    }

    template<typename I>
    void insert_range(Size position, I first, I last) {
        real_vector.insert(real_vector.begin() + position, first, last);
        pre_vector.insert(pre_vector.begin() + position, first, last);
        test();
    }

    void erase(Size position) {
        real_vector.erase(real_vector.begin() + position);
        pre_vector.erase(pre_vector.begin() + position);
        test();
    }

    void erase(Size first, Size last) {
        real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
        pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
        test();
    }

    void update(Size pos, const T& value) {
        real_vector[pos] = value;
        pre_vector[pos] = value;
        test();
    }

    void push_back(const T& value) {
        real_vector.push_back(value);
        pre_vector.push_back(value);
        test();
    }

    void pop_back() {
        real_vector.pop_back();
        pre_vector.pop_back();
        test();
    }

    void clear() {
        real_vector.clear();
        pre_vector.clear();
    }

    void assign(Size n, const T& value) {
        real_vector.assign(n, value);
        pre_vector.assign(n, value);
    }

    Size size() {
        return real_vector.size();
    }

    Size capacity() {
        return pre_vector.capacity();
    }

    void shrink_to_fit() {
        pre_vector.shrink_to_fit();
        test();
    }

    void swap() {
        real_vector.swap(real_vector_alt);
        pre_vector.swap(pre_vector_alt);
        test();
    }
};

BOOST_AUTO_TEST_CASE(PrevectorTestInt)
{
    for (int j = 0; j < 64; j++) {
        prevector_tester<8, int> test;
        for (int i = 0; i < 2048; i++) {
            int r = insecure_rand();
            if ((r % 4) == 0) {
                test.insert(insecure_rand() % (test.size() + 1), insecure_rand());
            }
            if (test.size() > 0 && ((r >> 2) % 4) == 1) {
                test.erase(insecure_rand() % test.size());
            }
            if (((r >> 4) % 8) == 2) {
                int new_size = std::max<int>(0, std::min<int>(30, test.size() + (insecure_rand() % 5) - 2));
                test.resize(new_size);
            }
            if (((r >> 7) % 8) == 3) {
                test.insert(insecure_rand() % (test.size() + 1), 1 + (insecure_rand() % 2), insecure_rand());
            }
            if (((r >> 10) % 8) == 4) {
                int del = std::min<int>(test.size(), 1 + (insecure_rand() % 2));
                int beg = insecure_rand() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            if (((r >> 13) % 16) == 5) {
                test.push_back(insecure_rand());
            }
            if (test.size() > 0 && ((r >> 17) % 16) == 6) {
                test.pop_back();
            }
            if (((r >> 21) % 32) == 7) {
                int values[4];
                int num = 1 + (insecure_rand() % 4);
                for (int i = 0; i < num; i++) {
                    values[i] = insecure_rand();
                }
                test.insert_range(insecure_rand() % (test.size() + 1), values, values + num);
            }
            if (((r >> 26) % 32) == 8) {
                int del = std::min<int>(test.size(), 1 + (insecure_rand() % 4));
                int beg = insecure_rand() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            r = insecure_rand();
            if (r % 32 == 9) {
                test.reserve(insecure_rand() % 32);
            }
            if ((r >> 5) % 64 == 10) {
                test.shrink_to_fit();
            }
            if (test.size() > 0) {
                test.update(insecure_rand() % test.size(), insecure_rand());
            }
            if (((r >> 11) % 1024) == 11) {
                test.clear();
            }
            if (((r >> 21) % 512) == 12) {
                test.assign(insecure_rand() % 32, insecure_rand());
            }
            if (((r >> 15) % 64) == 3) {
                test.swap();
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Minimal fix to slow prevector tests as stopgap measure<commit_after>// Copyright (c) 2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <vector>
#include "prevector.h"
#include "random.h"

#include "serialize.h"
#include "streams.h"

#include "test/test_dash.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup)

template<unsigned int N, typename T>
class prevector_tester {
    typedef std::vector<T> realtype;
    realtype real_vector;
    realtype real_vector_alt;

    typedef prevector<N, T> pretype;
    pretype pre_vector;
    pretype pre_vector_alt;

    typedef typename pretype::size_type Size;
    bool passed = true;
    uint32_t insecure_rand_Rz_cache;
    uint32_t insecure_rand_Rw_cache;

    template <typename A, typename B>
        void local_check_equal(A a, B b)
        {
            local_check(a == b);
        }
    void local_check(bool b)
    {
        passed &= b;
    }
    void test() {
        const pretype& const_pre_vector = pre_vector;
        local_check_equal(real_vector.size(), pre_vector.size());
        local_check_equal(real_vector.empty(), pre_vector.empty());
        for (Size s = 0; s < real_vector.size(); s++) {
             local_check(real_vector[s] == pre_vector[s]);
             local_check(&(pre_vector[s]) == &(pre_vector.begin()[s]));
             local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s));
             local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
        }
        // local_check(realtype(pre_vector) == real_vector);
        local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
        local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
        size_t pos = 0;
        BOOST_FOREACH(const T& v, pre_vector) {
             local_check(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
             local_check(v == real_vector[--pos]);
        }
        BOOST_FOREACH(const T& v, const_pre_vector) {
             local_check(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
             local_check(v == real_vector[--pos]);
        }
        CDataStream ss1(SER_DISK, 0);
        CDataStream ss2(SER_DISK, 0);
        ss1 << real_vector;
        ss2 << pre_vector;
        local_check_equal(ss1.size(), ss2.size());
        for (Size s = 0; s < ss1.size(); s++) {
            local_check_equal(ss1[s], ss2[s]);
        }
    }

public:
    void resize(Size s) {
        real_vector.resize(s);
        local_check_equal(real_vector.size(), s);
        pre_vector.resize(s);
        local_check_equal(pre_vector.size(), s);
        test();
    }

    void reserve(Size s) {
        real_vector.reserve(s);
        local_check(real_vector.capacity() >= s);
        pre_vector.reserve(s);
        local_check(pre_vector.capacity() >= s);
        test();
    }

    void insert(Size position, const T& value) {
        real_vector.insert(real_vector.begin() + position, value);
        pre_vector.insert(pre_vector.begin() + position, value);
        test();
    }

    void insert(Size position, Size count, const T& value) {
        real_vector.insert(real_vector.begin() + position, count, value);
        pre_vector.insert(pre_vector.begin() + position, count, value);
        test();
    }

    template<typename I>
    void insert_range(Size position, I first, I last) {
        real_vector.insert(real_vector.begin() + position, first, last);
        pre_vector.insert(pre_vector.begin() + position, first, last);
        test();
    }

    void erase(Size position) {
        real_vector.erase(real_vector.begin() + position);
        pre_vector.erase(pre_vector.begin() + position);
        test();
    }

    void erase(Size first, Size last) {
        real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
        pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
        test();
    }

    void update(Size pos, const T& value) {
        real_vector[pos] = value;
        pre_vector[pos] = value;
        test();
    }

    void push_back(const T& value) {
        real_vector.push_back(value);
        pre_vector.push_back(value);
        test();
    }

    void pop_back() {
        real_vector.pop_back();
        pre_vector.pop_back();
        test();
    }

    void clear() {
        real_vector.clear();
        pre_vector.clear();
    }

    void assign(Size n, const T& value) {
        real_vector.assign(n, value);
        pre_vector.assign(n, value);
    }

    Size size() {
        return real_vector.size();
    }

    Size capacity() {
        return pre_vector.capacity();
    }

    void shrink_to_fit() {
        pre_vector.shrink_to_fit();
        test();
    }

    void swap() {
        real_vector.swap(real_vector_alt);
        pre_vector.swap(pre_vector_alt);
        test();
    }
    ~prevector_tester() {
        BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: "
                << insecure_rand_Rz_cache
                << ", insecure_rand_Rw: "
                << insecure_rand_Rw_cache);
    }
    prevector_tester() {
        seed_insecure_rand();
        insecure_rand_Rz_cache = insecure_rand_Rz;
        insecure_rand_Rw_cache = insecure_rand_Rw;
    }
};

BOOST_AUTO_TEST_CASE(PrevectorTestInt)
{
    for (int j = 0; j < 64; j++) {
        prevector_tester<8, int> test;
        for (int i = 0; i < 2048; i++) {
            int r = insecure_rand();
            if ((r % 4) == 0) {
                test.insert(insecure_rand() % (test.size() + 1), insecure_rand());
            }
            if (test.size() > 0 && ((r >> 2) % 4) == 1) {
                test.erase(insecure_rand() % test.size());
            }
            if (((r >> 4) % 8) == 2) {
                int new_size = std::max<int>(0, std::min<int>(30, test.size() + (insecure_rand() % 5) - 2));
                test.resize(new_size);
            }
            if (((r >> 7) % 8) == 3) {
                test.insert(insecure_rand() % (test.size() + 1), 1 + (insecure_rand() % 2), insecure_rand());
            }
            if (((r >> 10) % 8) == 4) {
                int del = std::min<int>(test.size(), 1 + (insecure_rand() % 2));
                int beg = insecure_rand() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            if (((r >> 13) % 16) == 5) {
                test.push_back(insecure_rand());
            }
            if (test.size() > 0 && ((r >> 17) % 16) == 6) {
                test.pop_back();
            }
            if (((r >> 21) % 32) == 7) {
                int values[4];
                int num = 1 + (insecure_rand() % 4);
                for (int i = 0; i < num; i++) {
                    values[i] = insecure_rand();
                }
                test.insert_range(insecure_rand() % (test.size() + 1), values, values + num);
            }
            if (((r >> 26) % 32) == 8) {
                int del = std::min<int>(test.size(), 1 + (insecure_rand() % 4));
                int beg = insecure_rand() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            r = insecure_rand();
            if (r % 32 == 9) {
                test.reserve(insecure_rand() % 32);
            }
            if ((r >> 5) % 64 == 10) {
                test.shrink_to_fit();
            }
            if (test.size() > 0) {
                test.update(insecure_rand() % test.size(), insecure_rand());
            }
            if (((r >> 11) % 1024) == 11) {
                test.clear();
            }
            if (((r >> 21) % 512) == 12) {
                test.assign(insecure_rand() % 32, insecure_rand());
            }
            if (((r >> 15) % 64) == 3) {
                test.swap();
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#define MATH_BULLET_INTEROP
#include "DebugOperatorNew.h"
#include "btBulletDynamicsCommon.h"
#include "PhysicsModule.h"
#include "PhysicsWorld.h"
#include "PhysicsUtils.h"
#include "Profiler.h"
#include "Scene.h"
#include "OgreWorld.h"
#include "EC_RigidBody.h"
#include "LoggingFunctions.h"
#include "Geometry/LineSegment.h"

#include <Ogre.h>
#include "MemoryLeakCheck.h"

namespace Physics
{

void TickCallback(btDynamicsWorld *world, btScalar timeStep)
{
    static_cast<Physics::PhysicsWorld*>(world->getWorldUserInfo())->ProcessPostTick(timeStep);
}

PhysicsWorld::PhysicsWorld(ScenePtr scene, bool isClient) :
    scene_(scene),
    collisionConfiguration_(0),
    collisionDispatcher_(0),
    broadphase_(0),
    solver_(0),
    world_(0),
    physicsUpdatePeriod_(1.0f / 60.0f),
    maxSubSteps_(6), // If fps is below 10, we start to slow down physics
    isClient_(isClient),
    runPhysics_(true),
    drawDebugGeometry_(false),
    drawDebugManuallySet_(false),
    debugDrawMode_(0),
    cachedOgreWorld_(0)
{
    collisionConfiguration_ = new btDefaultCollisionConfiguration();
    collisionDispatcher_ = new btCollisionDispatcher(collisionConfiguration_);
    broadphase_ = new btDbvtBroadphase();
    solver_ = new btSequentialImpulseConstraintSolver();
    world_ = new btDiscreteDynamicsWorld(collisionDispatcher_, broadphase_, solver_, collisionConfiguration_);
    world_->setDebugDrawer(this);
    world_->setInternalTickCallback(TickCallback, (void*)this, false);
}

PhysicsWorld::~PhysicsWorld()
{
    SAFE_DELETE(world_);
    SAFE_DELETE(solver_);
    SAFE_DELETE(broadphase_);
    SAFE_DELETE(collisionDispatcher_);
    SAFE_DELETE(collisionConfiguration_);
}

void PhysicsWorld::SetPhysicsUpdatePeriod(float updatePeriod)
{
    // Allow max.1000 fps
    if (updatePeriod <= 0.001f)
        updatePeriod = 0.001f;
    physicsUpdatePeriod_ = updatePeriod;
}

void PhysicsWorld::SetMaxSubSteps(int steps)
{
    if (steps > 0)
        maxSubSteps_ = steps;
}

void PhysicsWorld::SetGravity(const float3& gravity)
{
    world_->setGravity(gravity);
}

float3 PhysicsWorld::Gravity() const
{
    return world_->getGravity();
}

btDiscreteDynamicsWorld* PhysicsWorld::BulletWorld() const
{
    return world_;
}

void PhysicsWorld::Simulate(f64 frametime)
{
    if (!runPhysics_)
        return;

    PROFILE(PhysicsWorld_Simulate);

    emit AboutToUpdate((float)frametime);

    {
        PROFILE(Bullet_stepSimulation); ///\note Do not delete or rename this PROFILE() block. The DebugStats profiler uses this string as a label to know where to inject the Bullet internal profiling data.
        world_->stepSimulation((float)frametime, maxSubSteps_, physicsUpdatePeriod_);
    }

    // Automatically enable debug geometry if at least one debug-enabled rigidbody. Automatically disable if no debug-enabled rigidbodies
    // However, do not do this if user has used the physicsdebug console command
    if (!drawDebugManuallySet_)
    {
        if ((!drawDebugGeometry_) && (!debugRigidBodies_.empty()))
            SetDebugGeometryEnabled(true);
        if ((drawDebugGeometry_) && (debugRigidBodies_.empty()))
            SetDebugGeometryEnabled(false);
    }

    if (drawDebugGeometry_)
        DrawDebugGeometry();
}

void PhysicsWorld::ProcessPostTick(float substeptime)
{
    PROFILE(PhysicsWorld_ProcessPostTick);
    // Check contacts and send collision signals for them
    int numManifolds = collisionDispatcher_->getNumManifolds();

    std::set<std::pair<btCollisionObject*, btCollisionObject*> > currentCollisions;

    if (numManifolds > 0)
    {
        PROFILE(PhysicsWorld_SendCollisions);

        for(int i = 0; i < numManifolds; ++i)
        {
            btPersistentManifold* contactManifold = collisionDispatcher_->getManifoldByIndexInternal(i);
            int numContacts = contactManifold->getNumContacts();
            if (numContacts == 0)
                continue;

            btCollisionObject* objectA = static_cast<btCollisionObject*>(contactManifold->getBody0());
            btCollisionObject* objectB = static_cast<btCollisionObject*>(contactManifold->getBody1());
            std::pair<btCollisionObject*, btCollisionObject*> objectPair;
            if (objectA < objectB)
                objectPair = std::make_pair(objectA, objectB);
            else
                objectPair = std::make_pair(objectB, objectA);

            EC_RigidBody* bodyA = static_cast<EC_RigidBody*>(objectA->getUserPointer());
            EC_RigidBody* bodyB = static_cast<EC_RigidBody*>(objectB->getUserPointer());

            // We are only interested in collisions where both EC_RigidBody components are known
            if (!bodyA || !bodyB)
            {
                LogError("Inconsistent Bullet physics scene state! An object exists in the physics scene which does not have an associated EC_RigidBody!");
                continue;
            }
            // Also, both bodies should have valid parent entities
            Entity* entityA = bodyA->ParentEntity();
            Entity* entityB = bodyB->ParentEntity();
            if (!entityA || !entityB)
            {
                LogError("Inconsistent Bullet physics scene state! A parentless EC_RigidBody exists in the physics scene!");
                continue;
            }
            // Check that at least one of the bodies is active
            if (!objectA->isActive() && !objectB->isActive())
                continue;

            bool newCollision = previousCollisions_.find(objectPair) == previousCollisions_.end();

            for(int j = 0; j < numContacts; ++j)
            {
                btManifoldPoint& point = contactManifold->getContactPoint(j);

                float3 position = point.m_positionWorldOnB;
                float3 normal = point.m_normalWorldOnB;
                float distance = point.m_distance1;
                float impulse = point.m_appliedImpulse;

                {
                    PROFILE(PhysicsWorld_emit_PhysicsCollision);
                    emit PhysicsCollision(entityA, entityB, position, normal, distance, impulse, newCollision);
                }
                bodyA->EmitPhysicsCollision(entityB, position, normal, distance, impulse, newCollision);
                bodyB->EmitPhysicsCollision(entityA, position, normal, distance, impulse, newCollision);

                // Report newCollision = true only for the first contact, in case there are several contacts, and application does some logic depending on it
                // (for example play a sound -> avoid multiple sounds being played)
                newCollision = false;
            }

            currentCollisions.insert(objectPair);
        }
    }

    previousCollisions_ = currentCollisions;

    {
        PROFILE(PhysicsWorld_ProcessPostTick_Updated);
        emit Updated(substeptime);
    }
}

PhysicsRaycastResult* PhysicsWorld::Raycast(const float3& origin, const float3& direction, float maxdistance, int collisiongroup, int collisionmask)
{
    PROFILE(PhysicsWorld_Raycast);

    static PhysicsRaycastResult result;

    float3 normalizedDir = direction.Normalized();

    btCollisionWorld::ClosestRayResultCallback rayCallback(origin, origin + maxdistance * normalizedDir);
    rayCallback.m_collisionFilterGroup = collisiongroup;
    rayCallback.m_collisionFilterMask = collisionmask;

    world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);

    result.entity = 0;
    result.distance = 0;

    if (rayCallback.hasHit())
    {
        result.pos = rayCallback.m_hitPointWorld;
        result.normal = rayCallback.m_hitNormalWorld;
        result.distance = (result.pos - origin).Length();
        if (rayCallback.m_collisionObject)
        {
            EC_RigidBody* body = static_cast<EC_RigidBody*>(rayCallback.m_collisionObject->getUserPointer());
            if (body)
                result.entity = body->ParentEntity();
        }
    }

    return &result;
}

void PhysicsWorld::SetDebugGeometryEnabled(bool enable)
{
    if (scene_.expired() || !scene_.lock()->ViewEnabled() || drawDebugGeometry_ == enable)
        return;

    drawDebugGeometry_ = enable;
    if (!enable)
        setDebugMode(0);
    else
        setDebugMode(btIDebugDraw::DBG_DrawWireframe);
}

void PhysicsWorld::DrawDebugGeometry()
{
    if (!drawDebugGeometry_)
        return;

    PROFILE(PhysicsModule_DrawDebugGeometry);

    // Draw debug only for the active (visible) scene
    OgreWorldPtr ogreWorld = scene_.lock()->GetWorld<OgreWorld>();
    cachedOgreWorld_ = ogreWorld.get();
    if (!ogreWorld)
        return;
    if (!ogreWorld->IsActive())
        return;

    // Get all lines of the physics world
    world_->debugDrawWorld();
}

void PhysicsWorld::reportErrorWarning(const char* warningString)
{
    LogWarning("Physics: " + std::string(warningString));
}

void PhysicsWorld::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
{
    if (drawDebugGeometry_ && cachedOgreWorld_)
        cachedOgreWorld_->DebugDrawLine(from, to, color.x(), color.y(), color.z());
}

} // ~Physics

<commit_msg>Fixed crash in PhysicsWorld collision signal emit functions that occurred if scripts changed physics world state in a collision signal handler.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#define MATH_BULLET_INTEROP
#include "DebugOperatorNew.h"
#include "btBulletDynamicsCommon.h"
#include "PhysicsModule.h"
#include "PhysicsWorld.h"
#include "PhysicsUtils.h"
#include "Profiler.h"
#include "Scene.h"
#include "OgreWorld.h"
#include "EC_RigidBody.h"
#include "LoggingFunctions.h"
#include "Geometry/LineSegment.h"

#include <Ogre.h>
#include "MemoryLeakCheck.h"

namespace Physics
{

void TickCallback(btDynamicsWorld *world, btScalar timeStep)
{
    static_cast<Physics::PhysicsWorld*>(world->getWorldUserInfo())->ProcessPostTick(timeStep);
}

PhysicsWorld::PhysicsWorld(ScenePtr scene, bool isClient) :
    scene_(scene),
    collisionConfiguration_(0),
    collisionDispatcher_(0),
    broadphase_(0),
    solver_(0),
    world_(0),
    physicsUpdatePeriod_(1.0f / 60.0f),
    maxSubSteps_(6), // If fps is below 10, we start to slow down physics
    isClient_(isClient),
    runPhysics_(true),
    drawDebugGeometry_(false),
    drawDebugManuallySet_(false),
    debugDrawMode_(0),
    cachedOgreWorld_(0)
{
    collisionConfiguration_ = new btDefaultCollisionConfiguration();
    collisionDispatcher_ = new btCollisionDispatcher(collisionConfiguration_);
    broadphase_ = new btDbvtBroadphase();
    solver_ = new btSequentialImpulseConstraintSolver();
    world_ = new btDiscreteDynamicsWorld(collisionDispatcher_, broadphase_, solver_, collisionConfiguration_);
    world_->setDebugDrawer(this);
    world_->setInternalTickCallback(TickCallback, (void*)this, false);
}

PhysicsWorld::~PhysicsWorld()
{
    SAFE_DELETE(world_);
    SAFE_DELETE(solver_);
    SAFE_DELETE(broadphase_);
    SAFE_DELETE(collisionDispatcher_);
    SAFE_DELETE(collisionConfiguration_);
}

void PhysicsWorld::SetPhysicsUpdatePeriod(float updatePeriod)
{
    // Allow max.1000 fps
    if (updatePeriod <= 0.001f)
        updatePeriod = 0.001f;
    physicsUpdatePeriod_ = updatePeriod;
}

void PhysicsWorld::SetMaxSubSteps(int steps)
{
    if (steps > 0)
        maxSubSteps_ = steps;
}

void PhysicsWorld::SetGravity(const float3& gravity)
{
    world_->setGravity(gravity);
}

float3 PhysicsWorld::Gravity() const
{
    return world_->getGravity();
}

btDiscreteDynamicsWorld* PhysicsWorld::BulletWorld() const
{
    return world_;
}

void PhysicsWorld::Simulate(f64 frametime)
{
    if (!runPhysics_)
        return;

    PROFILE(PhysicsWorld_Simulate);

    emit AboutToUpdate((float)frametime);

    {
        PROFILE(Bullet_stepSimulation); ///\note Do not delete or rename this PROFILE() block. The DebugStats profiler uses this string as a label to know where to inject the Bullet internal profiling data.
        world_->stepSimulation((float)frametime, maxSubSteps_, physicsUpdatePeriod_);
    }

    // Automatically enable debug geometry if at least one debug-enabled rigidbody. Automatically disable if no debug-enabled rigidbodies
    // However, do not do this if user has used the physicsdebug console command
    if (!drawDebugManuallySet_)
    {
        if ((!drawDebugGeometry_) && (!debugRigidBodies_.empty()))
            SetDebugGeometryEnabled(true);
        if ((drawDebugGeometry_) && (debugRigidBodies_.empty()))
            SetDebugGeometryEnabled(false);
    }

    if (drawDebugGeometry_)
        DrawDebugGeometry();
}

void PhysicsWorld::ProcessPostTick(float substeptime)
{
    PROFILE(PhysicsWorld_ProcessPostTick);
    // Check contacts and send collision signals for them
    int numManifolds = collisionDispatcher_->getNumManifolds();

    std::set<std::pair<btCollisionObject*, btCollisionObject*> > currentCollisions;

    // Collect all collision signals to a list before emitting any of them, in case a collision
    // handler changes physics state before the loop below is over (which would lead into catastrophic
    // consequences)
    struct CollisionSignal
    {
        EC_RigidBody *bodyA;
        EC_RigidBody *bodyB;
        float3 position;
        float3 normal;
        float distance;
        float impulse;
        bool newCollision;
    };
    std::vector<CollisionSignal> collisions;
    collisions.reserve(numManifolds * 3); // Guess some initial memory size for the collision list.

    if (numManifolds > 0)
    {
        PROFILE(PhysicsWorld_SendCollisions);

        for(int i = 0; i < numManifolds; ++i)
        {
            btPersistentManifold* contactManifold = collisionDispatcher_->getManifoldByIndexInternal(i);
            int numContacts = contactManifold->getNumContacts();
            if (numContacts == 0)
                continue;

            btCollisionObject* objectA = static_cast<btCollisionObject*>(contactManifold->getBody0());
            btCollisionObject* objectB = static_cast<btCollisionObject*>(contactManifold->getBody1());
            std::pair<btCollisionObject*, btCollisionObject*> objectPair;
            if (objectA < objectB)
                objectPair = std::make_pair(objectA, objectB);
            else
                objectPair = std::make_pair(objectB, objectA);

            EC_RigidBody* bodyA = static_cast<EC_RigidBody*>(objectA->getUserPointer());
            EC_RigidBody* bodyB = static_cast<EC_RigidBody*>(objectB->getUserPointer());

            // We are only interested in collisions where both EC_RigidBody components are known
            if (!bodyA || !bodyB)
            {
                LogError("Inconsistent Bullet physics scene state! An object exists in the physics scene which does not have an associated EC_RigidBody!");
                continue;
            }
            // Also, both bodies should have valid parent entities
            Entity* entityA = bodyA->ParentEntity();
            Entity* entityB = bodyB->ParentEntity();
            if (!entityA || !entityB)
            {
                LogError("Inconsistent Bullet physics scene state! A parentless EC_RigidBody exists in the physics scene!");
                continue;
            }
            // Check that at least one of the bodies is active
            if (!objectA->isActive() && !objectB->isActive())
                continue;

            bool newCollision = previousCollisions_.find(objectPair) == previousCollisions_.end();

            for(int j = 0; j < numContacts; ++j)
            {
                btManifoldPoint& point = contactManifold->getContactPoint(j);

                CollisionSignal s;
                s.bodyA = bodyA;
                s.bodyB = bodyB;
                s.position = point.m_positionWorldOnB;
                s.normal = point.m_normalWorldOnB;
                s.distance = point.m_distance1;
                s.impulse = point.m_appliedImpulse;
                s.newCollision = newCollision;
                collisions.push_back(s);

                // Report newCollision = true only for the first contact, in case there are several contacts, and application does some logic depending on it
                // (for example play a sound -> avoid multiple sounds being played)
                newCollision = false;
            }

            currentCollisions.insert(objectPair);
        }
    }

    // Now fire all collision signals.
    {
        PROFILE(PhysicsWorld_emit_PhysicsCollisions);
        for(size_t i = 0; i < collisions.size(); ++i)
        {
            emit PhysicsCollision(collisions[i].bodyA->ParentEntity(), collisions[i].bodyB->ParentEntity(), collisions[i].position, collisions[i].normal, collisions[i].distance, collisions[i].impulse, collisions[i].newCollision);
            collisions[i].bodyA->EmitPhysicsCollision(collisions[i].bodyB->ParentEntity(), collisions[i].position, collisions[i].normal, collisions[i].distance, collisions[i].impulse, collisions[i].newCollision);
            collisions[i].bodyB->EmitPhysicsCollision(collisions[i].bodyA->ParentEntity(), collisions[i].position, collisions[i].normal, collisions[i].distance, collisions[i].impulse, collisions[i].newCollision);
        }
    }

    previousCollisions_ = currentCollisions;

    {
        PROFILE(PhysicsWorld_ProcessPostTick_Updated);
        emit Updated(substeptime);
    }
}

PhysicsRaycastResult* PhysicsWorld::Raycast(const float3& origin, const float3& direction, float maxdistance, int collisiongroup, int collisionmask)
{
    PROFILE(PhysicsWorld_Raycast);

    static PhysicsRaycastResult result;

    float3 normalizedDir = direction.Normalized();

    btCollisionWorld::ClosestRayResultCallback rayCallback(origin, origin + maxdistance * normalizedDir);
    rayCallback.m_collisionFilterGroup = collisiongroup;
    rayCallback.m_collisionFilterMask = collisionmask;

    world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);

    result.entity = 0;
    result.distance = 0;

    if (rayCallback.hasHit())
    {
        result.pos = rayCallback.m_hitPointWorld;
        result.normal = rayCallback.m_hitNormalWorld;
        result.distance = (result.pos - origin).Length();
        if (rayCallback.m_collisionObject)
        {
            EC_RigidBody* body = static_cast<EC_RigidBody*>(rayCallback.m_collisionObject->getUserPointer());
            if (body)
                result.entity = body->ParentEntity();
        }
    }

    return &result;
}

void PhysicsWorld::SetDebugGeometryEnabled(bool enable)
{
    if (scene_.expired() || !scene_.lock()->ViewEnabled() || drawDebugGeometry_ == enable)
        return;

    drawDebugGeometry_ = enable;
    if (!enable)
        setDebugMode(0);
    else
        setDebugMode(btIDebugDraw::DBG_DrawWireframe);
}

void PhysicsWorld::DrawDebugGeometry()
{
    if (!drawDebugGeometry_)
        return;

    PROFILE(PhysicsModule_DrawDebugGeometry);

    // Draw debug only for the active (visible) scene
    OgreWorldPtr ogreWorld = scene_.lock()->GetWorld<OgreWorld>();
    cachedOgreWorld_ = ogreWorld.get();
    if (!ogreWorld)
        return;
    if (!ogreWorld->IsActive())
        return;

    // Get all lines of the physics world
    world_->debugDrawWorld();
}

void PhysicsWorld::reportErrorWarning(const char* warningString)
{
    LogWarning("Physics: " + std::string(warningString));
}

void PhysicsWorld::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
{
    if (drawDebugGeometry_ && cachedOgreWorld_)
        cachedOgreWorld_->DebugDrawLine(from, to, color.x(), color.y(), color.z());
}

} // ~Physics

<|endoftext|>


<commit_before>// Copyright (c) 2012-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <random.h>
#include <scheduler.h>

#include <test/test_chaincoin.h>

#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(scheduler_tests)

static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delta, boost::chrono::system_clock::time_point rescheduleTime)
{
    {
        boost::unique_lock<boost::mutex> lock(mutex);
        counter += delta;
    }
    boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
    if (rescheduleTime != noTime) {
        CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
        s.schedule(f, rescheduleTime);
    }
}

static void MicroSleep(uint64_t n)
{
#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
    boost::this_thread::sleep_for(boost::chrono::microseconds(n));
#elif defined(HAVE_WORKING_BOOST_SLEEP)
    boost::this_thread::sleep(boost::posix_time::microseconds(n));
#else
    //should never get here
    #error missing boost sleep implementation
#endif
}

BOOST_AUTO_TEST_CASE(manythreads)
{
    // Stress test: hundreds of microsecond-scheduled tasks,
    // serviced by 10 threads.
    //
    // So... ten shared counters, which if all the tasks execute
    // properly will sum to the number of tasks done.
    // Each task adds or subtracts a random amount from one of the
    // counters, and then schedules another task 0-1000
    // microseconds in the future to subtract or add from
    // the counter -random_amount+1, so in the end the shared
    // counters should sum to the number of initial tasks performed.
    CScheduler microTasks;

    boost::mutex counterMutex[10];
    int counter[10] = { 0 };
    FastRandomContext rng(42);
    auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9]
    auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000]
    auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000]

    boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
    boost::chrono::system_clock::time_point now = start;
    boost::chrono::system_clock::time_point first, last;
    size_t nTasks = microTasks.getQueueInfo(first, last);
    BOOST_CHECK(nTasks == 0);

    for (int i = 0; i < 100; ++i) {
        boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
        boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
        int whichCounter = zeroToNine(rng);
        CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
                                             boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
                                             randomDelta(rng), tReschedule);
        microTasks.schedule(f, t);
    }
    nTasks = microTasks.getQueueInfo(first, last);
    BOOST_CHECK(nTasks == 100);
    BOOST_CHECK(first < last);
    BOOST_CHECK(last > now);

    // As soon as these are created they will start running and servicing the queue
    boost::thread_group microThreads;
    for (int i = 0; i < 5; i++)
        microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));

    MicroSleep(600);
    now = boost::chrono::system_clock::now();

    // More threads and more tasks:
    for (int i = 0; i < 5; i++)
        microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
    for (int i = 0; i < 100; i++) {
        boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
        boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
        int whichCounter = zeroToNine(rng);
        CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
                                             boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
                                             randomDelta(rng), tReschedule);
        microTasks.schedule(f, t);
    }

    // Drain the task queue then exit threads
    microTasks.stop(true);
    microThreads.join_all(); // ... wait until all the threads are done

    int counterSum = 0;
    for (int i = 0; i < 10; i++) {
        BOOST_CHECK(counter[i] != 0);
        counterSum += counter[i];
    }
    BOOST_CHECK_EQUAL(counterSum, 200);
}

BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
{
    CScheduler scheduler;

    // each queue should be well ordered with respect to itself but not other queues
    SingleThreadedSchedulerClient queue1(&scheduler);
    SingleThreadedSchedulerClient queue2(&scheduler);

    // create more threads than queues
    // if the queues only permit execution of one task at once then
    // the extra threads should effectively be doing nothing
    // if they don't we'll get out of order behaviour
    boost::thread_group threads;
    for (int i = 0; i < 5; ++i) {
        threads.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
    }

    // these are not atomic, if SinglethreadedSchedulerClient prevents
    // parallel execution at the queue level no synchronization should be required here
    int counter1 = 0;
    int counter2 = 0;

    // just simply count up on each queue - if execution is properly ordered then
    // the callbacks should run in exactly the order in which they were enqueued
    for (int i = 0; i < 100; ++i) {
        queue1.AddToProcessQueue([i, &counter1]() {
            BOOST_CHECK_EQUAL(i, counter1++);
        });

        queue2.AddToProcessQueue([i, &counter2]() {
            BOOST_CHECK_EQUAL(i, counter2++);
        });
    }

    // finish up
    scheduler.stop(true);
    threads.join_all();

    BOOST_CHECK_EQUAL(counter1, 100);
    BOOST_CHECK_EQUAL(counter2, 100);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Use assert when running from multithreaded code as BOOST_CHECK_* are not thread safe<commit_after>// Copyright (c) 2012-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <random.h>
#include <scheduler.h>

#include <test/test_chaincoin.h>

#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(scheduler_tests)

static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delta, boost::chrono::system_clock::time_point rescheduleTime)
{
    {
        boost::unique_lock<boost::mutex> lock(mutex);
        counter += delta;
    }
    boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
    if (rescheduleTime != noTime) {
        CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
        s.schedule(f, rescheduleTime);
    }
}

static void MicroSleep(uint64_t n)
{
#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
    boost::this_thread::sleep_for(boost::chrono::microseconds(n));
#elif defined(HAVE_WORKING_BOOST_SLEEP)
    boost::this_thread::sleep(boost::posix_time::microseconds(n));
#else
    //should never get here
    #error missing boost sleep implementation
#endif
}

BOOST_AUTO_TEST_CASE(manythreads)
{
    // Stress test: hundreds of microsecond-scheduled tasks,
    // serviced by 10 threads.
    //
    // So... ten shared counters, which if all the tasks execute
    // properly will sum to the number of tasks done.
    // Each task adds or subtracts a random amount from one of the
    // counters, and then schedules another task 0-1000
    // microseconds in the future to subtract or add from
    // the counter -random_amount+1, so in the end the shared
    // counters should sum to the number of initial tasks performed.
    CScheduler microTasks;

    boost::mutex counterMutex[10];
    int counter[10] = { 0 };
    FastRandomContext rng(42);
    auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9]
    auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000]
    auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000]

    boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
    boost::chrono::system_clock::time_point now = start;
    boost::chrono::system_clock::time_point first, last;
    size_t nTasks = microTasks.getQueueInfo(first, last);
    BOOST_CHECK(nTasks == 0);

    for (int i = 0; i < 100; ++i) {
        boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
        boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
        int whichCounter = zeroToNine(rng);
        CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
                                             boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
                                             randomDelta(rng), tReschedule);
        microTasks.schedule(f, t);
    }
    nTasks = microTasks.getQueueInfo(first, last);
    BOOST_CHECK(nTasks == 100);
    BOOST_CHECK(first < last);
    BOOST_CHECK(last > now);

    // As soon as these are created they will start running and servicing the queue
    boost::thread_group microThreads;
    for (int i = 0; i < 5; i++)
        microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));

    MicroSleep(600);
    now = boost::chrono::system_clock::now();

    // More threads and more tasks:
    for (int i = 0; i < 5; i++)
        microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
    for (int i = 0; i < 100; i++) {
        boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
        boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
        int whichCounter = zeroToNine(rng);
        CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
                                             boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
                                             randomDelta(rng), tReschedule);
        microTasks.schedule(f, t);
    }

    // Drain the task queue then exit threads
    microTasks.stop(true);
    microThreads.join_all(); // ... wait until all the threads are done

    int counterSum = 0;
    for (int i = 0; i < 10; i++) {
        BOOST_CHECK(counter[i] != 0);
        counterSum += counter[i];
    }
    BOOST_CHECK_EQUAL(counterSum, 200);
}

BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
{
    CScheduler scheduler;

    // each queue should be well ordered with respect to itself but not other queues
    SingleThreadedSchedulerClient queue1(&scheduler);
    SingleThreadedSchedulerClient queue2(&scheduler);

    // create more threads than queues
    // if the queues only permit execution of one task at once then
    // the extra threads should effectively be doing nothing
    // if they don't we'll get out of order behaviour
    boost::thread_group threads;
    for (int i = 0; i < 5; ++i) {
        threads.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
    }

    // these are not atomic, if SinglethreadedSchedulerClient prevents
    // parallel execution at the queue level no synchronization should be required here
    int counter1 = 0;
    int counter2 = 0;

    // just simply count up on each queue - if execution is properly ordered then
    // the callbacks should run in exactly the order in which they were enqueued
    for (int i = 0; i < 100; ++i) {
        queue1.AddToProcessQueue([i, &counter1]() {
            assert(i == counter1++);
        });

        queue2.AddToProcessQueue([i, &counter2]() {
            assert(i == counter2++);
        });
    }

    // finish up
    scheduler.stop(true);
    threads.join_all();

    BOOST_CHECK_EQUAL(counter1, 100);
    BOOST_CHECK_EQUAL(counter2, 100);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>