<commit_before>
#include "geometry.hpp"
#include "quadric.hpp"
#include "line.hpp"
#include "accurate_intersections.hpp"
#include "quadric_classify.hpp"
#include "timer.hpp"

#include <list>
#include <fstream>
#include <iomanip>

#include <signal.h>
#include <unistd.h>

struct GlobalVars {
  bool run = true;
} globals;

void sigInt(int signum) { globals.run = false; }

template <int dim, typename fptype>
std::list<Geometry::Quadric<dim, fptype>> parseQuadrics(
    const char *fname) {
  std::ifstream file(fname);
  if(!file.is_open()) {
    return std::list<Geometry::Quadric<dim, fptype>>();
  }
  using Qf = Geometry::Quadric<dim, fptype>;
  int qtypeCount[QuadricClassify::QUADT_ERRORINVALID];
  for(int i = 0; i < QuadricClassify::QUADT_ERRORINVALID;
      i++)
    qtypeCount[i] = 0;
  std::list<Qf> quads;
  int imQuads = 0;
  int numQuads = 0;
  while(!file.eof()) {
    Qf q;
    file >> q;
    QuadricClassify::QuadType type =
        QuadricClassify::classifyQuadric(q);
    if(!QuadricClassify::isImaginary(type) &&
       type != QuadricClassify::QUADT_ERROR &&
       type != QuadricClassify::QUADT_DEGENERATE &&
       type != QuadricClassify::QUADT_ERRORINVALID) {
      quads.push_back(q);
      qtypeCount[type]++;
    } else {
      std::cout << "Quadric " << numQuads
                << " is invalid, returned type "
                << QuadricClassify::QuadTypeNames[type]
                << "\n";
      imQuads++;
    }
    numQuads++;
  }
  for(int i = 0; i < QuadricClassify::QUADT_ERRORINVALID;
      i++) {
    std::cout << qtypeCount[i] << " "
              << QuadricClassify::QuadTypeNames[i] << "\n";
  }
  return quads;
}

bool isSameInt(mpfr::mpreal int1, mpfr::mpreal int2) {
  /* Use a heuristic on truth to determine whether adjacent
   * intersections occur at the same place.
   * This will basically be a threshold on the largest
   * different bit in the mantissa.
   */
  /* A relative heuristic does not work when one (or both!)
   * is 0 */
  if(int1 == 0.0 || int2 == 0.0) {
    constexpr const double eps = 0.000001;
    return (mpfr::fabs(int1 - int2) < eps);
  }
  mpfr::mpreal largest =
      mpfr::max(mpfr::fabs(int1), mpfr::fabs(int2));
  mp_exp_t largestExp = largest.get_exp();
  mpfr::mpreal diff = mpfr::fabs(int1 - int2);
  int p1 = int1.getPrecision(), p2 = int2.getPrecision();
  int minPrec = std::min(p1, p2);
  mp_exp_t maxExp = largestExp - minPrec * 1 / 48,
           diffExp = diff.get_exp();
  return maxExp >= diffExp;
}

template <typename ListFP, typename ListMP>
bool validateResults(ListFP &inter, ListMP &truth) {
  auto j = truth->begin();
  for(auto i = inter->begin();
      i != inter->end() || j != truth->end();) {
    /* First determine the length of the region of equal
     * intersections.
     * Then verify there's an equal number of
     * intersections in the approximately equal range and
     * that they correspond to the correct intersections.
     * If not, then print the intersection
     */
    if(j != truth->end()) {
      /* Create the region boundaries [sameBeg, sameEnd).
       * These are intersections which are probably the same
       */
      auto sameBeg = j;
      auto sameEnd = j;
      int regLen = 0;
      while(sameEnd != truth->end() &&
            isSameInt(j->intPos, sameEnd->intPos)) {
        sameEnd++;
        regLen++;
      }
      /* Increment i until it's not found in the region */
      int numInRegion = 0;
      bool isInRegion = true;
      while(i != inter->end() && isInRegion &&
            numInRegion < regLen) {
        j = sameBeg;
        while(j != sameEnd && i->q != j->q) j++;
        /* sameEnd is not in the region, so if j reaches it,
         * i isn't in the region */
        if(j == sameEnd) {
          isInRegion = false;
        } else {
          i++;
          numInRegion++;
        }
      }
      /* i isn't in the region.
       * Verify all elements in the region were used */
      if(regLen != numInRegion) {
        return false;
      }
      j = sameEnd;
    } else {
      int numRemaining = 0;
      while(i != inter->end()) {
        i++;
        numRemaining++;
      }
      return false;
    }
  }
  return true;
}

template <typename List>
int countIP(List inter) {
  int numIP = 0;
  for(auto i : *inter) numIP += i.incPrecCount();
  return numIP;
}

template <int dim, typename fptype>
using randLineGen =
    Geometry::Line<dim, fptype> (*)(std::mt19937_64 &rng);

template <int dim, typename fptype>
std::shared_ptr<std::list<Geometry::Intersection<
    dim, fptype>>> __attribute__((noinline))
runTest(std::list<Geometry::Quadric<dim, fptype>> &quads,
        Geometry::Line<dim, fptype> &line,
        Timer::Timer &timer) {
  const double eps = 0.75 / (2 * quads.size());
  timer.startTimer();
  auto inter =
      Geometry::sortIntersections(line, quads, fptype(eps));
  timer.stopTimer();
  return inter;
}

template <int dim, typename fptype>
void intersectionTest(
    std::list<Geometry::Quadric<dim, fptype>> &quads,
    std::ostream &results, const int numTests,
    randLineGen<dim, fptype> rlgf) {
  /* First build a scene of quadrics.
   * Then generate random lines on a disk centered at the
   * intersection of the cylinders.
   * Then sort the intersections
   * Finally validate them with a higher precision sort
   */
  using Vf = Geometry::Vector<dim, fptype>;
  using Pf = Geometry::Point<dim, fptype>;
  using Lf = Geometry::Line<dim, fptype>;
  using Qm = Geometry::Quadric<dim, mpfr::mpreal>;
  using Lm = Geometry::Line<dim, mpfr::mpreal>;
  constexpr const int machPrec =
      GenericFP::fpconvert<fptype>::precision;
  constexpr const int precMult = 24;
  constexpr const int truthPrec = precMult * machPrec;
  mpfr::mpreal::set_default_prec(truthPrec);
  std::list<Qm> truthQuads;
  /* Generate the quadrics */
  for(auto q : quads) {
    Qm quadMP(q);
    truthQuads.push_back(quadMP);
  }
  std::random_device rd;
  std::mt19937_64 engine(rd());
  Timer::Timer fp_time, mp_time;
  struct TimeArr {
    int fpns;
    int mpns;
    bool correct;
    int resNumIP;
    int mpNumIP;
  } *times = new struct TimeArr[numTests];
  /* Run the tests */
  int t;
  for(t = 0; t < numTests && globals.run; t++) {
    Lf line = rlgf(engine);
    Lm truthLine(line);
    constexpr const fptype eps =
        std::numeric_limits<fptype>::infinity();
    /* Then sort the intersections */
    auto inter = runTest(quads, line, fp_time);
    auto truth = runTest(truthQuads, truthLine, mp_time);
    times[t].fpns = fp_time.instant_ns();
    times[t].mpns = mp_time.instant_ns();
    times[t].correct = validateResults(inter, truth);
    times[t].resNumIP = countIP(inter);
    times[t].mpNumIP = countIP(truth);
  }
  /* Output all of the results */
  results << "Test #, Resultants, FP Time (ns), "
             "Increased Precs, MP Time (ns), Correct\n";
  int resTotIP = 0;
  int MPTotIP = 0;
  int totIncorrect = 0;
  for(int i = 0; i < t; i++) {
    results << i + 1 << ", " << times[i].resNumIP << ", "
            << times[i].fpns << ", " << times[i].mpNumIP
            << ", " << times[i].mpns << ", "
            << times[i].correct << "\n";
    resTotIP += times[i].resNumIP;
    MPTotIP += times[i].mpNumIP;
    totIncorrect += 1 - times[i].correct;
  }
  results << "\n"
          << "Total resultant computations: " << resTotIP
          << "\n"
          << "Total FP Time (s): " << fp_time.elapsed_s()
          << "." << std::setw(9) << std::setfill('0')
          << fp_time.elapsed_ns() << "\n"
          << "Total increased precision computations: "
          << MPTotIP << "\n"
          << "Total MP Time (s): " << mp_time.elapsed_s()
          << "." << std::setw(9) << std::setfill('0')
          << mp_time.elapsed_ns() << "\n";
  results << "Total potentially incorrect: " << totIncorrect
          << "\n";
  delete[] times;
}

void lockCPU() {
  const int numCPUs = sysconf(_SC_NPROCESSORS_ONLN);
  const int cpuSets =
      numCPUs / CPU_SETSIZE + ((numCPUs % CPU_SETSIZE) > 0);
  cpu_set_t *cpus = new cpu_set_t[cpuSets];
  const size_t cpuSize = sizeof(cpu_set_t[cpuSets]);
  sched_getaffinity(0, cpuSize, cpus);
  for(int i = 1; i < numCPUs; i++) CPU_CLR(i, cpus);
  CPU_SET(0, cpus);
  sched_setaffinity(0, cpuSize, cpus);
  delete[] cpus;
}

template <int dim, typename fptype>
Geometry::Line<dim, fptype> defRandLine(
    std::mt19937_64 &rng) {
  constexpr const fptype minPos = 0, maxPos = 2;
  std::uniform_real_distribution<fptype> genPos(minPos,
                                                maxPos);
  std::uniform_real_distribution<fptype> genDir(-1.0, 1.0);
  /* First build the line */
  Geometry::Vector<dim, fptype> lineDir;
  Geometry::Vector<dim, fptype> lineInt;
  for(int i = 0; i < dim; i++) {
    fptype tmp = genPos(rng);
    lineInt.set(i, tmp);
    tmp = genDir(rng);
    lineDir.set(i, tmp);
  }
  return Geometry::Line<dim, fptype>(
      Geometry::Point<dim, fptype>(lineInt), lineInt);
}

template <int dim, typename fptype>
Geometry::Line<dim, fptype> cylRandLine(
    std::mt19937_64 &rng) {
  constexpr const fptype minPos = 0.375, maxPos = 0.625;
  std::uniform_real_distribution<fptype> genPos(minPos,
                                                maxPos);
  std::uniform_real_distribution<fptype> genDir(-1.0, 1.0);
  /* First build the line */
  Geometry::Vector<dim, fptype> lineDir;
  Geometry::Vector<dim, fptype> lineInt;
  lineInt.set(1, genPos(rng));
  for(int i = 0; i < dim; i++) {
    lineInt.set(i, lineInt.get(1));
    lineDir.set(i, genDir(rng));
  }
  lineInt.set(0, genPos(rng));
  return Geometry::Line<dim, fptype>(
      Geometry::Point<dim, fptype>(lineInt), lineInt);
}

int main(int argc, char **argv) {
  using fptype = float;
  constexpr const int dim = 3;
  lockCPU();
  std::list<Geometry::Quadric<dim, fptype>> quads;
  const char *outFName = "results";
  int numTests = 1e4;
  randLineGen<dim, fptype> rlg = cylRandLine<dim, fptype>;
  if(argc > 1) {
    quads = parseQuadrics<dim, fptype>(argv[1]);
    rlg = defRandLine<dim, fptype>;
    if(argc > 2) {
      outFName = argv[2];
      if(argc > 3) numTests = atoi(argv[3]);
    }
  } else {
    quads = parseQuadrics<dim, fptype>("cylinders.csg");
  }
  std::ofstream results(outFName);
  signal(SIGINT, sigInt);
  intersectionTest(quads, results, numTests, defRandLine);
  return 0;
}
<commit_msg>Updated for gcc-6 by explicitly including random. Use a typename to specify the RNG algorithm<commit_after>
#include "geometry.hpp"
#include "quadric.hpp"
#include "line.hpp"
#include "accurate_intersections.hpp"
#include "quadric_classify.hpp"
#include "timer.hpp"

#include <list>
#include <fstream>
#include <iomanip>
#include <random>

#include <signal.h>
#include <unistd.h>

struct GlobalVars {
  bool run = true;
} globals;

void sigInt(int signum) { globals.run = false; }

template <int dim, typename fptype>
std::list<Geometry::Quadric<dim, fptype>> parseQuadrics(
    const char *fname) {
  std::ifstream file(fname);
  if(!file.is_open()) {
    return std::list<Geometry::Quadric<dim, fptype>>();
  }
  using Qf = Geometry::Quadric<dim, fptype>;
  int qtypeCount[QuadricClassify::QUADT_ERRORINVALID];
  for(int i = 0; i < QuadricClassify::QUADT_ERRORINVALID;
      i++)
    qtypeCount[i] = 0;
  std::list<Qf> quads;
  int imQuads = 0;
  int numQuads = 0;
  while(!file.eof()) {
    Qf q;
    file >> q;
    QuadricClassify::QuadType type =
        QuadricClassify::classifyQuadric(q);
    if(!QuadricClassify::isImaginary(type) &&
       type != QuadricClassify::QUADT_ERROR &&
       type != QuadricClassify::QUADT_DEGENERATE &&
       type != QuadricClassify::QUADT_ERRORINVALID) {
      quads.push_back(q);
      qtypeCount[type]++;
    } else {
      std::cout << "Quadric " << numQuads
                << " is invalid, returned type "
                << QuadricClassify::QuadTypeNames[type]
                << "\n";
      imQuads++;
    }
    numQuads++;
  }
  for(int i = 0; i < QuadricClassify::QUADT_ERRORINVALID;
      i++) {
    std::cout << qtypeCount[i] << " "
              << QuadricClassify::QuadTypeNames[i] << "\n";
  }
  return quads;
}

bool isSameInt(mpfr::mpreal int1, mpfr::mpreal int2) {
  /* Use a heuristic on truth to determine whether adjacent
   * intersections occur at the same place.
   * This will basically be a threshold on the largest
   * different bit in the mantissa.
   */
  /* A relative heuristic does not work when one (or both!)
   * is 0 */
  if(int1 == 0.0 || int2 == 0.0) {
    constexpr const double eps = 0.000001;
    return (mpfr::fabs(int1 - int2) < eps);
  }
  mpfr::mpreal largest =
      mpfr::max(mpfr::fabs(int1), mpfr::fabs(int2));
  mp_exp_t largestExp = largest.get_exp();
  mpfr::mpreal diff = mpfr::fabs(int1 - int2);
  int p1 = int1.getPrecision(), p2 = int2.getPrecision();
  int minPrec = std::min(p1, p2);
  mp_exp_t maxExp = largestExp - minPrec * 1 / 48,
           diffExp = diff.get_exp();
  return maxExp >= diffExp;
}

template <typename ListFP, typename ListMP>
bool validateResults(ListFP &inter, ListMP &truth) {
  auto j = truth->begin();
  for(auto i = inter->begin();
      i != inter->end() || j != truth->end();) {
    /* First determine the length of the region of equal
     * intersections.
     * Then verify there's an equal number of
     * intersections in the approximately equal range and
     * that they correspond to the correct intersections.
     * If not, then print the intersection
     */
    if(j != truth->end()) {
      /* Create the region boundaries [sameBeg, sameEnd).
       * These are intersections which are probably the same
       */
      auto sameBeg = j;
      auto sameEnd = j;
      int regLen = 0;
      while(sameEnd != truth->end() &&
            isSameInt(j->intPos, sameEnd->intPos)) {
        sameEnd++;
        regLen++;
      }
      /* Increment i until it's not found in the region */
      int numInRegion = 0;
      bool isInRegion = true;
      while(i != inter->end() && isInRegion &&
            numInRegion < regLen) {
        j = sameBeg;
        while(j != sameEnd && i->q != j->q) j++;
        /* sameEnd is not in the region, so if j reaches it,
         * i isn't in the region */
        if(j == sameEnd) {
          isInRegion = false;
        } else {
          i++;
          numInRegion++;
        }
      }
      /* i isn't in the region.
       * Verify all elements in the region were used */
      if(regLen != numInRegion) {
        return false;
      }
      j = sameEnd;
    } else {
      int numRemaining = 0;
      while(i != inter->end()) {
        i++;
        numRemaining++;
      }
      return false;
    }
  }
  return true;
}

template <typename List>
int countIP(List inter) {
  int numIP = 0;
  for(auto i : *inter) numIP += i.incPrecCount();
  return numIP;
}

using rngAlg = std::mt19937_64;

template <int dim, typename fptype>
using randLineGen =
    Geometry::Line<dim, fptype> (*)(rngAlg &rng);

template <int dim, typename fptype>
std::shared_ptr<std::list<Geometry::Intersection<
    dim, fptype>>> __attribute__((noinline))
runTest(std::list<Geometry::Quadric<dim, fptype>> &quads,
        Geometry::Line<dim, fptype> &line,
        Timer::Timer &timer) {
  const double eps = 0.75 / (2 * quads.size());
  timer.startTimer();
  auto inter =
      Geometry::sortIntersections(line, quads, fptype(eps));
  timer.stopTimer();
  return inter;
}

template <int dim, typename fptype>
void intersectionTest(
    std::list<Geometry::Quadric<dim, fptype>> &quads,
    std::ostream &results, const int numTests,
    randLineGen<dim, fptype> rlgf) {
  /* First build a scene of quadrics.
   * Then generate random lines on a disk centered at the
   * intersection of the cylinders.
   * Then sort the intersections
   * Finally validate them with a higher precision sort
   */
  using Vf = Geometry::Vector<dim, fptype>;
  using Pf = Geometry::Point<dim, fptype>;
  using Lf = Geometry::Line<dim, fptype>;
  using Qm = Geometry::Quadric<dim, mpfr::mpreal>;
  using Lm = Geometry::Line<dim, mpfr::mpreal>;
  constexpr const int machPrec =
      GenericFP::fpconvert<fptype>::precision;
  constexpr const int precMult = 24;
  constexpr const int truthPrec = precMult * machPrec;
  mpfr::mpreal::set_default_prec(truthPrec);
  std::list<Qm> truthQuads;
  /* Generate the quadrics */
  for(auto q : quads) {
    Qm quadMP(q);
    truthQuads.push_back(quadMP);
  }
  std::random_device rd;
  rngAlg engine(rd());
  Timer::Timer fp_time, mp_time;
  struct TimeArr {
    int fpns;
    int mpns;
    bool correct;
    int resNumIP;
    int mpNumIP;
  } *times = new struct TimeArr[numTests];
  /* Run the tests */
  int t;
  for(t = 0; t < numTests && globals.run; t++) {
    Lf line = rlgf(engine);
    Lm truthLine(line);
    constexpr const fptype eps =
        std::numeric_limits<fptype>::infinity();
    /* Then sort the intersections */
    auto inter = runTest(quads, line, fp_time);
    auto truth = runTest(truthQuads, truthLine, mp_time);
    times[t].fpns = fp_time.instant_ns();
    times[t].mpns = mp_time.instant_ns();
    times[t].correct = validateResults(inter, truth);
    times[t].resNumIP = countIP(inter);
    times[t].mpNumIP = countIP(truth);
  }
  /* Output all of the results */
  results << "Test #, Resultants, FP Time (ns), "
             "Increased Precs, MP Time (ns), Correct\n";
  int resTotIP = 0;
  int MPTotIP = 0;
  int totIncorrect = 0;
  for(int i = 0; i < t; i++) {
    results << i + 1 << ", " << times[i].resNumIP << ", "
            << times[i].fpns << ", " << times[i].mpNumIP
            << ", " << times[i].mpns << ", "
            << times[i].correct << "\n";
    resTotIP += times[i].resNumIP;
    MPTotIP += times[i].mpNumIP;
    totIncorrect += 1 - times[i].correct;
  }
  results << "\n"
          << "Total resultant computations: " << resTotIP
          << "\n"
          << "Total FP Time (s): " << fp_time.elapsed_s()
          << "." << std::setw(9) << std::setfill('0')
          << fp_time.elapsed_ns() << "\n"
          << "Total increased precision computations: "
          << MPTotIP << "\n"
          << "Total MP Time (s): " << mp_time.elapsed_s()
          << "." << std::setw(9) << std::setfill('0')
          << mp_time.elapsed_ns() << "\n";
  results << "Total potentially incorrect: " << totIncorrect
          << "\n";
  delete[] times;
}

void lockCPU() {
  const int numCPUs = sysconf(_SC_NPROCESSORS_ONLN);
  const int cpuSets =
      numCPUs / CPU_SETSIZE + ((numCPUs % CPU_SETSIZE) > 0);
  cpu_set_t *cpus = new cpu_set_t[cpuSets];
  const size_t cpuSize = sizeof(cpu_set_t[cpuSets]);
  sched_getaffinity(0, cpuSize, cpus);
  for(int i = 1; i < numCPUs; i++) CPU_CLR(i, cpus);
  CPU_SET(0, cpus);
  sched_setaffinity(0, cpuSize, cpus);
  delete[] cpus;
}

template <int dim, typename fptype>
Geometry::Line<dim, fptype> defRandLine(
    rngAlg &rng) {
  constexpr const fptype minPos = 0, maxPos = 2;
  std::uniform_real_distribution<fptype> genPos(minPos,
                                                maxPos);
  std::uniform_real_distribution<fptype> genDir(-1.0, 1.0);
  /* First build the line */
  Geometry::Vector<dim, fptype> lineDir;
  Geometry::Vector<dim, fptype> lineInt;
  for(int i = 0; i < dim; i++) {
    fptype tmp = genPos(rng);
    lineInt.set(i, tmp);
    tmp = genDir(rng);
    lineDir.set(i, tmp);
  }
  return Geometry::Line<dim, fptype>(
      Geometry::Point<dim, fptype>(lineInt), lineInt);
}

template <int dim, typename fptype>
Geometry::Line<dim, fptype> cylRandLine(
    rngAlg &rng) {
  constexpr const fptype minPos = 0.375, maxPos = 0.625;
  std::uniform_real_distribution<fptype> genPos(minPos,
                                                maxPos);
  std::uniform_real_distribution<fptype> genDir(-1.0, 1.0);
  /* First build the line */
  Geometry::Vector<dim, fptype> lineDir;
  Geometry::Vector<dim, fptype> lineInt;
  lineInt.set(1, genPos(rng));
  for(int i = 0; i < dim; i++) {
    lineInt.set(i, lineInt.get(1));
    lineDir.set(i, genDir(rng));
  }
  lineInt.set(0, genPos(rng));
  return Geometry::Line<dim, fptype>(
      Geometry::Point<dim, fptype>(lineInt), lineInt);
}

int main(int argc, char **argv) {
  using fptype = float;
  constexpr const int dim = 3;
  lockCPU();
  std::list<Geometry::Quadric<dim, fptype>> quads;
  const char *outFName = "results";
  int numTests = 1e4;
  randLineGen<dim, fptype> rlg = cylRandLine<dim, fptype>;
  if(argc > 1) {
    quads = parseQuadrics<dim, fptype>(argv[1]);
    rlg = defRandLine<dim, fptype>;
    if(argc > 2) {
      outFName = argv[2];
      if(argc > 3) numTests = atoi(argv[3]);
    }
  } else {
    quads = parseQuadrics<dim, fptype>("cylinders.csg");
  }
  std::ofstream results(outFName);
  signal(SIGINT, sigInt);
  intersectionTest(quads, results, numTests, defRandLine);
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/import_thunk_list.hpp"

#include <utility>

#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include <windows.h>

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/pelib/pe_file.hpp"
#include "hadesmem/pelib/import_thunk.hpp"

namespace hadesmem
{

struct ImportThunkIterator::Impl
{
  explicit Impl(Process const& process, PeFile const& pe_file)
    HADESMEM_NOEXCEPT
    : process_(&process),
    pe_file_(&pe_file),
    import_thunk_()
  { }

  Process const* process_;
  PeFile const* pe_file_;
  boost::optional<ImportThunk> import_thunk_;
};

ImportThunkIterator::ImportThunkIterator() HADESMEM_NOEXCEPT
  : impl_()
{ }

ImportThunkIterator::ImportThunkIterator(Process const& process,
  PeFile const& pe_file, DWORD first_thunk)
  : impl_(new Impl(process, pe_file))
{
  try
  {
    auto const thunk_ptr = reinterpret_cast<PIMAGE_THUNK_DATA>(RvaToVa(
      process, pe_file, first_thunk));
    impl_->import_thunk_ = ImportThunk(process, pe_file, thunk_ptr);
  }
  catch (std::exception const& /*e*/)
  {
    // TODO: Check whether this is the right thing to do. We should only
    // flag as the 'end' once we've actually reached the end of the list. If
    // the iteration fails we should throw an exception.
    impl_.reset();
  }
}

ImportThunkIterator::ImportThunkIterator(ImportThunkIterator const& other)
  HADESMEM_NOEXCEPT
  : impl_(other.impl_)
{ }

ImportThunkIterator& ImportThunkIterator::operator=(
  ImportThunkIterator const& other) HADESMEM_NOEXCEPT
{
  impl_ = other.impl_;

  return *this;
}

ImportThunkIterator::ImportThunkIterator(ImportThunkIterator&& other)
  HADESMEM_NOEXCEPT
  : impl_(std::move(other.impl_))
{ }

ImportThunkIterator& ImportThunkIterator::operator=(
  ImportThunkIterator&& other) HADESMEM_NOEXCEPT
{
  impl_ = std::move(other.impl_);

  return *this;
}

ImportThunkIterator::~ImportThunkIterator()
{ }

ImportThunkIterator::reference ImportThunkIterator::operator*() const
  HADESMEM_NOEXCEPT
{
  BOOST_ASSERT(impl_.get());
  return *impl_->import_thunk_;
}

ImportThunkIterator::pointer ImportThunkIterator::operator->() const
  HADESMEM_NOEXCEPT
{
  BOOST_ASSERT(impl_.get());
  return &*impl_->import_thunk_;
}

ImportThunkIterator& ImportThunkIterator::operator++()
{
  try
  {
    BOOST_ASSERT(impl_.get());

    auto const cur_base = reinterpret_cast<PIMAGE_THUNK_DATA>(
      impl_->import_thunk_->GetBase());
    impl_->import_thunk_ = ImportThunk(*impl_->process_, *impl_->pe_file_,
      cur_base + 1);

    if (!impl_->import_thunk_->GetAddressOfData())
    {
      impl_.reset();
      return *this;
    }
  }
  catch (std::exception const& /*e*/)
  {
    // TODO: Check whether this is the right thing to do. We should only
    // flag as the 'end' once we've actually reached the end of the list. If
    // the iteration fails we should throw an exception.
    impl_.reset();
  }

  return *this;
}

ImportThunkIterator ImportThunkIterator::operator++(int)
{
  ImportThunkIterator iter(*this);
  ++*this;
  return iter;
}

bool ImportThunkIterator::operator==(ImportThunkIterator const& other) const
  HADESMEM_NOEXCEPT
{
  return impl_ == other.impl_;
}

bool ImportThunkIterator::operator!=(ImportThunkIterator const& other) const
  HADESMEM_NOEXCEPT
{
  return !(*this == other);
}

struct ImportThunkList::Impl
{
  Impl(Process const& process, PeFile const& pe_file, DWORD first_thunk)
    : process_(&process),
    pe_file_(&pe_file),
    first_thunk_(first_thunk)
  { }

  Process const* process_;
  PeFile const* pe_file_;
  DWORD first_thunk_;
};

ImportThunkList::ImportThunkList(Process const& process, PeFile const& pe_file,
  DWORD first_thunk)
  : impl_(new Impl(process, pe_file, first_thunk))
{ }

ImportThunkList::ImportThunkList(ImportThunkList const& other)
  : impl_(new Impl(*other.impl_))
{ }

ImportThunkList& ImportThunkList::operator=(ImportThunkList const& other)
{
  impl_ = std::unique_ptr<Impl>(new Impl(*other.impl_));

  return *this;
}

ImportThunkList::ImportThunkList(ImportThunkList&& other) HADESMEM_NOEXCEPT
  : impl_(std::move(other.impl_))
{ }

ImportThunkList& ImportThunkList::operator=(ImportThunkList&& other)
  HADESMEM_NOEXCEPT
{
  impl_ = std::move(other.impl_);

  return *this;
}

ImportThunkList::~ImportThunkList()
{ }

ImportThunkList::iterator ImportThunkList::begin()
{
  return ImportThunkList::iterator(*impl_->process_, *impl_->pe_file_,
    impl_->first_thunk_);
}

ImportThunkList::const_iterator ImportThunkList::begin() const
{
  return ImportThunkList::iterator(*impl_->process_, *impl_->pe_file_,
    impl_->first_thunk_);
}

ImportThunkList::iterator ImportThunkList::end() HADESMEM_NOEXCEPT
{
  return ImportThunkList::iterator();
}

ImportThunkList::const_iterator ImportThunkList::end() const HADESMEM_NOEXCEPT
{
  return ImportThunkList::iterator();
}

}
<commit_msg>* Fix enumeration of a valid but empty import thunk list.<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/import_thunk_list.hpp"

#include <utility>

#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include <windows.h>

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/pelib/pe_file.hpp"
#include "hadesmem/pelib/import_thunk.hpp"

namespace hadesmem
{

struct ImportThunkIterator::Impl
{
  explicit Impl(Process const& process, PeFile const& pe_file)
    HADESMEM_NOEXCEPT
    : process_(&process),
    pe_file_(&pe_file),
    import_thunk_()
  { }

  Process const* process_;
  PeFile const* pe_file_;
  boost::optional<ImportThunk> import_thunk_;
};

ImportThunkIterator::ImportThunkIterator() HADESMEM_NOEXCEPT
  : impl_()
{ }

ImportThunkIterator::ImportThunkIterator(Process const& process,
  PeFile const& pe_file, DWORD first_thunk)
  : impl_(new Impl(process, pe_file))
{
  try
  {
    auto const thunk_ptr = reinterpret_cast<PIMAGE_THUNK_DATA>(RvaToVa(
      process, pe_file, first_thunk));
    impl_->import_thunk_ = ImportThunk(process, pe_file, thunk_ptr);
    if (!impl_->import_thunk_->GetAddressOfData())
    {
      impl_.reset();
    }
  }
  catch (std::exception const& /*e*/)
  {
    // TODO: Check whether this is the right thing to do. We should only
    // flag as the 'end' once we've actually reached the end of the list. If
    // the iteration fails we should throw an exception.
    impl_.reset();
  }
}

ImportThunkIterator::ImportThunkIterator(ImportThunkIterator const& other)
  HADESMEM_NOEXCEPT
  : impl_(other.impl_)
{ }

ImportThunkIterator& ImportThunkIterator::operator=(
  ImportThunkIterator const& other) HADESMEM_NOEXCEPT
{
  impl_ = other.impl_;

  return *this;
}

ImportThunkIterator::ImportThunkIterator(ImportThunkIterator&& other)
  HADESMEM_NOEXCEPT
  : impl_(std::move(other.impl_))
{ }

ImportThunkIterator& ImportThunkIterator::operator=(
  ImportThunkIterator&& other) HADESMEM_NOEXCEPT
{
  impl_ = std::move(other.impl_);

  return *this;
}

ImportThunkIterator::~ImportThunkIterator()
{ }

ImportThunkIterator::reference ImportThunkIterator::operator*() const
  HADESMEM_NOEXCEPT
{
  BOOST_ASSERT(impl_.get());
  return *impl_->import_thunk_;
}

ImportThunkIterator::pointer ImportThunkIterator::operator->() const
  HADESMEM_NOEXCEPT
{
  BOOST_ASSERT(impl_.get());
  return &*impl_->import_thunk_;
}

ImportThunkIterator& ImportThunkIterator::operator++()
{
  try
  {
    BOOST_ASSERT(impl_.get());

    auto const cur_base = reinterpret_cast<PIMAGE_THUNK_DATA>(
      impl_->import_thunk_->GetBase());
    impl_->import_thunk_ = ImportThunk(*impl_->process_, *impl_->pe_file_,
      cur_base + 1);

    if (!impl_->import_thunk_->GetAddressOfData())
    {
      impl_.reset();
      return *this;
    }
  }
  catch (std::exception const& /*e*/)
  {
    // TODO: Check whether this is the right thing to do. We should only
    // flag as the 'end' once we've actually reached the end of the list. If
    // the iteration fails we should throw an exception.
    impl_.reset();
  }

  return *this;
}

ImportThunkIterator ImportThunkIterator::operator++(int)
{
  ImportThunkIterator iter(*this);
  ++*this;
  return iter;
}

bool ImportThunkIterator::operator==(ImportThunkIterator const& other) const
  HADESMEM_NOEXCEPT
{
  return impl_ == other.impl_;
}

bool ImportThunkIterator::operator!=(ImportThunkIterator const& other) const
  HADESMEM_NOEXCEPT
{
  return !(*this == other);
}

struct ImportThunkList::Impl
{
  Impl(Process const& process, PeFile const& pe_file, DWORD first_thunk)
    : process_(&process),
    pe_file_(&pe_file),
    first_thunk_(first_thunk)
  { }

  Process const* process_;
  PeFile const* pe_file_;
  DWORD first_thunk_;
};

ImportThunkList::ImportThunkList(Process const& process, PeFile const& pe_file,
  DWORD first_thunk)
  : impl_(new Impl(process, pe_file, first_thunk))
{ }

ImportThunkList::ImportThunkList(ImportThunkList const& other)
  : impl_(new Impl(*other.impl_))
{ }

ImportThunkList& ImportThunkList::operator=(ImportThunkList const& other)
{
  impl_ = std::unique_ptr<Impl>(new Impl(*other.impl_));

  return *this;
}

ImportThunkList::ImportThunkList(ImportThunkList&& other) HADESMEM_NOEXCEPT
  : impl_(std::move(other.impl_))
{ }

ImportThunkList& ImportThunkList::operator=(ImportThunkList&& other)
  HADESMEM_NOEXCEPT
{
  impl_ = std::move(other.impl_);

  return *this;
}

ImportThunkList::~ImportThunkList()
{ }

ImportThunkList::iterator ImportThunkList::begin()
{
  return ImportThunkList::iterator(*impl_->process_, *impl_->pe_file_,
    impl_->first_thunk_);
}

ImportThunkList::const_iterator ImportThunkList::begin() const
{
  return ImportThunkList::iterator(*impl_->process_, *impl_->pe_file_,
    impl_->first_thunk_);
}

ImportThunkList::iterator ImportThunkList::end() HADESMEM_NOEXCEPT
{
  return ImportThunkList::iterator();
}

ImportThunkList::const_iterator ImportThunkList::end() const HADESMEM_NOEXCEPT
{
  return ImportThunkList::iterator();
}

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/qpointer.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qbasictimer.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qscrollbar.h>
#include <QtGui/qx11info_x11.h>

#include "qgraphicsvideoitem.h"

#ifdef Q_OS_SYMBIAN
#define QGRAPHICSVIDEOITEM_ROTATION_SUPPORT
#endif

#include <qmediaobject.h>
#include <qmediaservice.h>
#include <qvideowindowcontrol.h>

QT_BEGIN_NAMESPACE

#define DEBUG_GFX_VIDEO_ITEM

class QGraphicsVideoItemPrivate : public QObject
{
public:
    QGraphicsVideoItemPrivate()
        : q_ptr(0)
        , mediaObject(0)
        , service(0)
        , windowControl(0)
        , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
        , aspectRatioMode(Qt::KeepAspectRatio)
        , rect(0.0, 0.0, 320, 240)
        , videoWidget(0)
    {
    }

    QGraphicsVideoItem *q_ptr;

    QMediaObject *mediaObject;
    QMediaService *service;
    QVideoWindowControl *windowControl;
    QPointer<QGraphicsView> currentView;
    QList<QPointer<QObject> > eventFilterTargets;
    QGraphicsView::ViewportUpdateMode savedViewportUpdateMode;

    Qt::AspectRatioMode aspectRatioMode;
    QRectF rect;
    QRectF boundingRect;
    QRectF displayRect;
    QSizeF nativeSize;

    QWidget *videoWidget;

    bool eventFilter(QObject *object, QEvent *event);
    void updateEventFilters();

    void setWidget(QWidget *widget);
    void clearService();
    void updateRects();
    void updateLastFrame();

    void _q_present();
    void _q_updateNativeSize();
    void _q_serviceDestroyed();
    void _q_mediaObjectDestroyed();
};

void QGraphicsVideoItemPrivate::_q_present()
{

}

bool QGraphicsVideoItemPrivate::eventFilter(QObject *object, QEvent *event)
{
    if (windowControl && object == videoWidget && QEvent::WinIdChange == event->type()) {
        windowControl->setWinId(videoWidget->effectiveWinId());
    } else {
        bool updateEventFiltersRequired = false;
        bool refreshDisplayRequired = false;
        foreach (QPointer<QObject> target, eventFilterTargets) {
            if (object == target.data()) {
                switch (event->type()) {
                case QEvent::ParentChange:
                    updateEventFiltersRequired = true;
                    refreshDisplayRequired = true;
                    break;
                case QEvent::Move:
                case QEvent::Resize:
                    refreshDisplayRequired = true;
                    break;
                default: ;
                }
            }
        }
        if (updateEventFiltersRequired)
            updateEventFilters();
#ifdef Q_OS_SYMBIAN
        if (refreshDisplayRequired && windowControl)
            QMetaObject::invokeMethod(windowControl, "refreshDisplay");
#endif
    }
    return false;
}

void QGraphicsVideoItemPrivate::setWidget(QWidget *widget)
{
    if (videoWidget != widget) {
        videoWidget = widget;
        if (widget) {
            windowControl->setWinId(widget->winId());
            widget->installEventFilter(this);
        }
    }
}

void QGraphicsVideoItemPrivate::clearService()
{
    if (windowControl) {
        QObject::disconnect(windowControl, SIGNAL(nativeSizeChanged()), q_ptr, SLOT(_q_updateNativeSize()));
        service->releaseControl(windowControl);
        windowControl = 0;
    }

    if (service) {
        QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
        service = 0;
    }
}

void QGraphicsVideoItemPrivate::updateRects()
{
    q_ptr->prepareGeometryChange();
    QSizeF videoSize;
    if (nativeSize.isEmpty()) {
        videoSize = rect.size();
    } else if (aspectRatioMode == Qt::IgnoreAspectRatio) {
        videoSize = rect.size();
    } else {
        // KeepAspectRatio or KeepAspectRatioByExpanding
        videoSize = nativeSize;
        videoSize.scale(rect.size(), aspectRatioMode);
    }
    displayRect = QRectF(QPointF(0, 0), videoSize);
    displayRect.moveCenter(rect.center());
    boundingRect = displayRect.intersected(rect);
}

void QGraphicsVideoItemPrivate::updateLastFrame()
{
}

void QGraphicsVideoItemPrivate::updateEventFilters()
{
    // In order to determine when the absolute screen position of the item
    // changes, we need to receive move events sent to m_currentView
    // or any of its ancestors.
    foreach (QPointer<QObject> target, eventFilterTargets)
        if (target)
            target->removeEventFilter(this);
    eventFilterTargets.clear();
    QObject *target = currentView;
    while (target) {
        target->installEventFilter(this);
        eventFilterTargets.append(target);
        target = target->parent();
    }
}

void QGraphicsVideoItemPrivate::_q_updateNativeSize()
{
    const QSize size = windowControl->nativeSize();
    if (nativeSize != size) {
        nativeSize = size;

        updateRects();
        emit q_ptr->nativeSizeChanged(nativeSize);
    }
}

void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
{
    windowControl = 0;
    service = 0;
}

void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
{
    mediaObject = 0;

    clearService();
}

QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
    : QGraphicsObject(parent)
    , d_ptr(new QGraphicsVideoItemPrivate)
{
    d_ptr->q_ptr = this;

    setCacheMode(NoCache);
    setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
}

QGraphicsVideoItem::~QGraphicsVideoItem()
{
    if (d_ptr->windowControl) {
        d_ptr->service->releaseControl(d_ptr->windowControl);
    }

    if (d_ptr->currentView)
        d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);

    delete d_ptr;
}

QMediaObject *QGraphicsVideoItem::mediaObject() const
{
    return d_func()->mediaObject;
}

bool QGraphicsVideoItem::setMediaObject(QMediaObject *object)
{
    Q_D(QGraphicsVideoItem);

    if (object == d->mediaObject)
        return true;

    d->clearService();

    d->mediaObject = object;

    if (d->mediaObject) {
        d->service = d->mediaObject->service();

        if (d->service) {
            d->windowControl = qobject_cast<QVideoWindowControl *>(
                    d->service->requestControl(QVideoWindowControl_iid));

            if (d->windowControl != 0) {
                connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed()));
                connect(d->windowControl, SIGNAL(nativeSizeChanged()), SLOT(_q_updateNativeSize()));
                d->windowControl->setAspectRatioMode(Qt::IgnoreAspectRatio);
                //d->windowControl->setProperty("colorKey", QVariant(QColor(16,7,2)));
                d->windowControl->setProperty("autopaintColorKey", QVariant(false));

                d->updateRects();
                return true;
            } else {
                qWarning() << "Service doesn't support QVideoWindowControl, overlay item failed";
            }
        }
    }

    d->mediaObject = 0;
    return false;
}

Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
{
    return d_func()->aspectRatioMode;
}

void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
{
    Q_D(QGraphicsVideoItem);

    d->aspectRatioMode = mode;
    d->updateRects();
}

QPointF QGraphicsVideoItem::offset() const
{
    return d_func()->rect.topLeft();
}

void QGraphicsVideoItem::setOffset(const QPointF &offset)
{
    Q_D(QGraphicsVideoItem);

    d->rect.moveTo(offset);
    d->updateRects();
}

QSizeF QGraphicsVideoItem::size() const
{
    return d_func()->rect.size();
}

void QGraphicsVideoItem::setSize(const QSizeF &size)
{
    Q_D(QGraphicsVideoItem);

    d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
    d->updateRects();
}

QSizeF QGraphicsVideoItem::nativeSize() const
{
    return d_func()->nativeSize;
}

QRectF QGraphicsVideoItem::boundingRect() const
{
    return d_func()->boundingRect;
}

void QGraphicsVideoItem::paint(
        QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
#ifdef DEBUG_GFX_VIDEO_ITEM
    qDebug() << "QGraphicsVideoItem::paint";
#endif

    Q_UNUSED(option);
    Q_D(QGraphicsVideoItem);

    QGraphicsView *view = 0;
    if (scene() && !scene()->views().isEmpty())
        view = scene()->views().first();

    //it's necessary to switch vieport update mode to FullViewportUpdate
    //otherwise the video item area can be just scrolled without notifying overlay
    //about geometry changes
    if (view != d->currentView) {
        if (d->currentView) {
            d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
        }

        d->currentView = view;
        if (view) {
            d->savedViewportUpdateMode = view->viewportUpdateMode();
            view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
        }
        d->updateEventFilters();
    }

    QColor colorKey = Qt::black;

    if (d->windowControl != 0 && widget != 0) {
        d->setWidget(widget);

        QTransform transform = painter->combinedTransform();
        QRect overlayRect = transform.mapRect(d->displayRect).toRect();
        QRect currentSurfaceRect = d->windowControl->displayRect();

        if (currentSurfaceRect != overlayRect) {
#ifdef DEBUG_GFX_VIDEO_ITEM
            qDebug() << "set video display rect:" << overlayRect;
#endif
            d->windowControl->setDisplayRect(overlayRect);
        }

        colorKey = d->windowControl->property("colorKey").value<QColor>();
#ifdef QGRAPHICSVIDEOITEM_ROTATION_SUPPORT
        const qreal angle = transform.map(QLineF(0, 0, 1, 0)).angle();
        d->windowControl->setProperty("rotation", QVariant::fromValue<qreal>(angle));
#endif
    }

    if (colorKey.alpha() != 255)
        painter->setCompositionMode(QPainter::CompositionMode_Source);
    painter->fillRect(d->boundingRect, colorKey);
}

QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    Q_D(QGraphicsVideoItem);

    switch (change) {
    case ItemScenePositionHasChanged:
        update(boundingRect());
        break;
    case ItemVisibleChange:
        //move overlay out of the screen if video item becomes invisible
        if (d->windowControl != 0 && !value.toBool())
            d->windowControl->setDisplayRect(QRect(-1,-1,1,1));
        break;
    default:
        break;
    }

    return QGraphicsItem::itemChange(change, value);
}

void QGraphicsVideoItem::timerEvent(QTimerEvent *event)
{
    QGraphicsObject::timerEvent(event);
}

#include "moc_qgraphicsvideoitem.cpp"
QT_END_NAMESPACE
<commit_msg>QtMultimedia: micro-optimisation<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/qpointer.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qbasictimer.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qscrollbar.h>
#include <QtGui/qx11info_x11.h>

#include "qgraphicsvideoitem.h"

#ifdef Q_OS_SYMBIAN
#define QGRAPHICSVIDEOITEM_ROTATION_SUPPORT
#endif

#include <qmediaobject.h>
#include <qmediaservice.h>
#include <qvideowindowcontrol.h>

QT_BEGIN_NAMESPACE

#define DEBUG_GFX_VIDEO_ITEM

class QGraphicsVideoItemPrivate : public QObject
{
public:
    QGraphicsVideoItemPrivate()
        : q_ptr(0)
        , mediaObject(0)
        , service(0)
        , windowControl(0)
        , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
        , aspectRatioMode(Qt::KeepAspectRatio)
        , rect(0.0, 0.0, 320, 240)
        , videoWidget(0)
    {
    }

    QGraphicsVideoItem *q_ptr;

    QMediaObject *mediaObject;
    QMediaService *service;
    QVideoWindowControl *windowControl;
    QPointer<QGraphicsView> currentView;
    QList<QPointer<QObject> > eventFilterTargets;
    QGraphicsView::ViewportUpdateMode savedViewportUpdateMode;

    Qt::AspectRatioMode aspectRatioMode;
    QRectF rect;
    QRectF boundingRect;
    QRectF displayRect;
    QSizeF nativeSize;

    QWidget *videoWidget;

    bool eventFilter(QObject *object, QEvent *event);
    void updateEventFilters();

    void setWidget(QWidget *widget);
    void clearService();
    void updateRects();
    void updateLastFrame();

    void _q_present();
    void _q_updateNativeSize();
    void _q_serviceDestroyed();
    void _q_mediaObjectDestroyed();
};

void QGraphicsVideoItemPrivate::_q_present()
{

}

bool QGraphicsVideoItemPrivate::eventFilter(QObject *object, QEvent *event)
{
    if (windowControl && object == videoWidget && QEvent::WinIdChange == event->type()) {
        windowControl->setWinId(videoWidget->effectiveWinId());
    } else {
        bool updateEventFiltersRequired = false;
        bool refreshDisplayRequired = false;
        foreach (const QPointer<QObject> &target, eventFilterTargets) {
            if (object == target.data()) {
                switch (event->type()) {
                case QEvent::ParentChange:
                    updateEventFiltersRequired = true;
                    refreshDisplayRequired = true;
                    break;
                case QEvent::Move:
                case QEvent::Resize:
                    refreshDisplayRequired = true;
                    break;
                default: ;
                }
            }
        }
        if (updateEventFiltersRequired)
            updateEventFilters();
#ifdef Q_OS_SYMBIAN
        if (refreshDisplayRequired && windowControl)
            QMetaObject::invokeMethod(windowControl, "refreshDisplay");
#endif
    }
    return false;
}

void QGraphicsVideoItemPrivate::setWidget(QWidget *widget)
{
    if (videoWidget != widget) {
        videoWidget = widget;
        if (widget) {
            windowControl->setWinId(widget->winId());
            widget->installEventFilter(this);
        }
    }
}

void QGraphicsVideoItemPrivate::clearService()
{
    if (windowControl) {
        QObject::disconnect(windowControl, SIGNAL(nativeSizeChanged()), q_ptr, SLOT(_q_updateNativeSize()));
        service->releaseControl(windowControl);
        windowControl = 0;
    }

    if (service) {
        QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
        service = 0;
    }
}

void QGraphicsVideoItemPrivate::updateRects()
{
    q_ptr->prepareGeometryChange();
    QSizeF videoSize;
    if (nativeSize.isEmpty()) {
        videoSize = rect.size();
    } else if (aspectRatioMode == Qt::IgnoreAspectRatio) {
        videoSize = rect.size();
    } else {
        // KeepAspectRatio or KeepAspectRatioByExpanding
        videoSize = nativeSize;
        videoSize.scale(rect.size(), aspectRatioMode);
    }
    displayRect = QRectF(QPointF(0, 0), videoSize);
    displayRect.moveCenter(rect.center());
    boundingRect = displayRect.intersected(rect);
}

void QGraphicsVideoItemPrivate::updateLastFrame()
{
}

void QGraphicsVideoItemPrivate::updateEventFilters()
{
    // In order to determine when the absolute screen position of the item
    // changes, we need to receive move events sent to m_currentView
    // or any of its ancestors.
    foreach (QPointer<QObject> target, eventFilterTargets)
        if (target)
            target->removeEventFilter(this);
    eventFilterTargets.clear();
    QObject *target = currentView;
    while (target) {
        target->installEventFilter(this);
        eventFilterTargets.append(target);
        target = target->parent();
    }
}

void QGraphicsVideoItemPrivate::_q_updateNativeSize()
{
    const QSize size = windowControl->nativeSize();
    if (nativeSize != size) {
        nativeSize = size;

        updateRects();
        emit q_ptr->nativeSizeChanged(nativeSize);
    }
}

void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
{
    windowControl = 0;
    service = 0;
}

void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
{
    mediaObject = 0;

    clearService();
}

QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
    : QGraphicsObject(parent)
    , d_ptr(new QGraphicsVideoItemPrivate)
{
    d_ptr->q_ptr = this;

    setCacheMode(NoCache);
    setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
}

QGraphicsVideoItem::~QGraphicsVideoItem()
{
    if (d_ptr->windowControl) {
        d_ptr->service->releaseControl(d_ptr->windowControl);
    }

    if (d_ptr->currentView)
        d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);

    delete d_ptr;
}

QMediaObject *QGraphicsVideoItem::mediaObject() const
{
    return d_func()->mediaObject;
}

bool QGraphicsVideoItem::setMediaObject(QMediaObject *object)
{
    Q_D(QGraphicsVideoItem);

    if (object == d->mediaObject)
        return true;

    d->clearService();

    d->mediaObject = object;

    if (d->mediaObject) {
        d->service = d->mediaObject->service();

        if (d->service) {
            d->windowControl = qobject_cast<QVideoWindowControl *>(
                    d->service->requestControl(QVideoWindowControl_iid));

            if (d->windowControl != 0) {
                connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed()));
                connect(d->windowControl, SIGNAL(nativeSizeChanged()), SLOT(_q_updateNativeSize()));
                d->windowControl->setAspectRatioMode(Qt::IgnoreAspectRatio);
                //d->windowControl->setProperty("colorKey", QVariant(QColor(16,7,2)));
                d->windowControl->setProperty("autopaintColorKey", QVariant(false));

                d->updateRects();
                return true;
            } else {
                qWarning() << "Service doesn't support QVideoWindowControl, overlay item failed";
            }
        }
    }

    d->mediaObject = 0;
    return false;
}

Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
{
    return d_func()->aspectRatioMode;
}

void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
{
    Q_D(QGraphicsVideoItem);

    d->aspectRatioMode = mode;
    d->updateRects();
}

QPointF QGraphicsVideoItem::offset() const
{
    return d_func()->rect.topLeft();
}

void QGraphicsVideoItem::setOffset(const QPointF &offset)
{
    Q_D(QGraphicsVideoItem);

    d->rect.moveTo(offset);
    d->updateRects();
}

QSizeF QGraphicsVideoItem::size() const
{
    return d_func()->rect.size();
}

void QGraphicsVideoItem::setSize(const QSizeF &size)
{
    Q_D(QGraphicsVideoItem);

    d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
    d->updateRects();
}

QSizeF QGraphicsVideoItem::nativeSize() const
{
    return d_func()->nativeSize;
}

QRectF QGraphicsVideoItem::boundingRect() const
{
    return d_func()->boundingRect;
}

void QGraphicsVideoItem::paint(
        QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
#ifdef DEBUG_GFX_VIDEO_ITEM
    qDebug() << "QGraphicsVideoItem::paint";
#endif

    Q_UNUSED(option);
    Q_D(QGraphicsVideoItem);

    QGraphicsView *view = 0;
    if (scene() && !scene()->views().isEmpty())
        view = scene()->views().first();

    //it's necessary to switch vieport update mode to FullViewportUpdate
    //otherwise the video item area can be just scrolled without notifying overlay
    //about geometry changes
    if (view != d->currentView) {
        if (d->currentView) {
            d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
        }

        d->currentView = view;
        if (view) {
            d->savedViewportUpdateMode = view->viewportUpdateMode();
            view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
        }
        d->updateEventFilters();
    }

    QColor colorKey = Qt::black;

    if (d->windowControl != 0 && widget != 0) {
        d->setWidget(widget);

        QTransform transform = painter->combinedTransform();
        QRect overlayRect = transform.mapRect(d->displayRect).toRect();
        QRect currentSurfaceRect = d->windowControl->displayRect();

        if (currentSurfaceRect != overlayRect) {
#ifdef DEBUG_GFX_VIDEO_ITEM
            qDebug() << "set video display rect:" << overlayRect;
#endif
            d->windowControl->setDisplayRect(overlayRect);
        }

        colorKey = d->windowControl->property("colorKey").value<QColor>();
#ifdef QGRAPHICSVIDEOITEM_ROTATION_SUPPORT
        const qreal angle = transform.map(QLineF(0, 0, 1, 0)).angle();
        d->windowControl->setProperty("rotation", QVariant::fromValue<qreal>(angle));
#endif
    }

    if (colorKey.alpha() != 255)
        painter->setCompositionMode(QPainter::CompositionMode_Source);
    painter->fillRect(d->boundingRect, colorKey);
}

QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    Q_D(QGraphicsVideoItem);

    switch (change) {
    case ItemScenePositionHasChanged:
        update(boundingRect());
        break;
    case ItemVisibleChange:
        //move overlay out of the screen if video item becomes invisible
        if (d->windowControl != 0 && !value.toBool())
            d->windowControl->setDisplayRect(QRect(-1,-1,1,1));
        break;
    default:
        break;
    }

    return QGraphicsItem::itemChange(change, value);
}

void QGraphicsVideoItem::timerEvent(QTimerEvent *event)
{
    QGraphicsObject::timerEvent(event);
}

#include "moc_qgraphicsvideoitem.cpp"
QT_END_NAMESPACE
<|endoftext|>


<commit_before>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2011, Willow Garage, Inc.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Willow Garage nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/* Author: Ioan Sucan */

#include "ompl/tools/multiplan/ParallelPlan.h"
#include "ompl/geometric/PathHybridization.h"

ompl::tools::ParallelPlan::ParallelPlan(const base::ProblemDefinitionPtr &pdef) :
    pdef_(pdef), phybrid_(new geometric::PathHybridization(pdef->getSpaceInformation()))
{
}

ompl::tools::ParallelPlan::~ParallelPlan()
{
}

void ompl::tools::ParallelPlan::addPlanner(const base::PlannerPtr &planner)
{
    if (planner && planner->getSpaceInformation().get() != pdef_->getSpaceInformation().get())
        throw Exception("Planner instance does not match space information");
    if (planner->getProblemDefinition().get() != pdef_.get())
        planner->setProblemDefinition(pdef_);
    planners_.push_back(planner);
}

void ompl::tools::ParallelPlan::addPlannerAllocator(const base::PlannerAllocator &pa)
{
    base::PlannerPtr planner = pa(pdef_->getSpaceInformation());
    planner->setProblemDefinition(pdef_);
    planners_.push_back(planner);
}

void ompl::tools::ParallelPlan::clearPlanners()
{
    planners_.clear();
}

void ompl::tools::ParallelPlan::clearHybridizationPaths()
{
    phybrid_->clear();
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(double solveTime, bool hybridize)
{
    return solve(solveTime, 1, planners_.size(), hybridize);
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(double solveTime, std::size_t minSolCount, std::size_t maxSolCount, bool hybridize)
{
    return solve(base::timedPlannerTerminationCondition(solveTime, std::min(solveTime / 100.0, 0.1)), minSolCount, maxSolCount, hybridize);
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(const base::PlannerTerminationCondition &ptc, bool hybridize)
{
    return solve(ptc, 1, planners_.size(), hybridize);
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(const base::PlannerTerminationCondition &ptc, std::size_t minSolCount,
  std::size_t maxSolCount, bool hybridize)
{
    if (!pdef_->getSpaceInformation()->isSetup())
        pdef_->getSpaceInformation()->setup();
    foundSolCount_ = 0;

    time::point start = time::now();
    std::vector<boost::thread*> threads(planners_.size());

    // Decide if we are combining solutions or just taking the first one
    if (hybridize)
        for (std::size_t i = 0 ; i < threads.size() ; ++i)
            threads[i] = new boost::thread(boost::bind(&ParallelPlan::solveMore, this, planners_[i].get(), minSolCount, maxSolCount, &ptc));
    else
        for (std::size_t i = 0 ; i < threads.size() ; ++i)
            threads[i] = new boost::thread(boost::bind(&ParallelPlan::solveOne, this, planners_[i].get(), minSolCount, &ptc));

    for (std::size_t i = 0 ; i < threads.size() ; ++i)
    {
        threads[i]->join();
        delete threads[i];
    }

    if (hybridize)
    {
        if (phybrid_->pathCount() > 1)
            if (const base::PathPtr &hsol = phybrid_->getHybridPath())
            {
                geometric::PathGeometric *pg = static_cast<geometric::PathGeometric*>(hsol.get());
                double difference = 0.0;
                bool approximate = !pdef_->getGoal()->isSatisfied(pg->getStates().back(), &difference);
                pdef_->addSolutionPath(hsol, approximate, difference, phybrid_->getName()); // name this solution after the hybridization algorithm
            }
    }

    if (pdef_->hasSolution())
        OMPL_INFORM("ParallelPlan::solve(): Solution found by one or more threads in %f seconds", time::seconds(time::now() - start));
    else
        OMPL_WARN("ParallelPlan::solve(): Unable to find solution by any of the threads in %f seconds", time::seconds(time::now() - start));

    return base::PlannerStatus(pdef_->hasSolution(), pdef_->hasApproximateSolution());
}

void ompl::tools::ParallelPlan::solveOne(base::Planner *planner, std::size_t minSolCount, const base::PlannerTerminationCondition *ptc)
{
    OMPL_DEBUG("ParallelPlam.solveOne starting planner %s", planner->getName().c_str());

    time::point start = time::now();
    if (planner->solve(*ptc))
    {
        double duration = time::seconds(time::now() - start);
        foundSolCountLock_.lock();
        unsigned int nrSol = ++foundSolCount_;
        foundSolCountLock_.unlock();
        if (nrSol >= minSolCount)
            ptc->terminate();
        OMPL_DEBUG("ParallelPlan.solveOne: Solution found by %s in %lf seconds", planner->getName().c_str(), duration);
    }
}

void ompl::tools::ParallelPlan::solveMore(base::Planner *planner, std::size_t minSolCount, std::size_t maxSolCount,
  const base::PlannerTerminationCondition *ptc)
{
    OMPL_DEBUG("ParallelPlan.solveMore: starting planner %s", planner->getName().c_str());

    time::point start = time::now();
    if (planner->solve(*ptc))
    {
        double duration = time::seconds(time::now() - start);
        foundSolCountLock_.lock();
        unsigned int nrSol = ++foundSolCount_;
        foundSolCountLock_.unlock();

        if (nrSol >= maxSolCount)
            ptc->terminate();

        OMPL_DEBUG("ParallelPlan.solveMore: Solution found by %s in %lf seconds", planner->getName().c_str(), duration);

        const std::vector<base::PlannerSolution> &paths = pdef_->getSolutions();

        boost::mutex::scoped_lock slock(phlock_);
        start = time::now();
        unsigned int attempts = 0;
        for (std::size_t i = 0 ; i < paths.size() ; ++i)
            attempts += phybrid_->recordPath(paths[i].path_, false);

        if (phybrid_->pathCount() >= minSolCount)
            phybrid_->computeHybridPath();

        duration = time::seconds(time::now() - start);
        OMPL_DEBUG("ParallelPlan.solveMore: Spent %f seconds hybridizing %u solution paths (attempted %u connections between paths)", duration,
          (unsigned int)phybrid_->pathCount(), attempts);
    }
}
<commit_msg>Spellcheck<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2011, Willow Garage, Inc.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Willow Garage nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/* Author: Ioan Sucan */

#include "ompl/tools/multiplan/ParallelPlan.h"
#include "ompl/geometric/PathHybridization.h"

ompl::tools::ParallelPlan::ParallelPlan(const base::ProblemDefinitionPtr &pdef) :
    pdef_(pdef), phybrid_(new geometric::PathHybridization(pdef->getSpaceInformation()))
{
}

ompl::tools::ParallelPlan::~ParallelPlan()
{
}

void ompl::tools::ParallelPlan::addPlanner(const base::PlannerPtr &planner)
{
    if (planner && planner->getSpaceInformation().get() != pdef_->getSpaceInformation().get())
        throw Exception("Planner instance does not match space information");
    if (planner->getProblemDefinition().get() != pdef_.get())
        planner->setProblemDefinition(pdef_);
    planners_.push_back(planner);
}

void ompl::tools::ParallelPlan::addPlannerAllocator(const base::PlannerAllocator &pa)
{
    base::PlannerPtr planner = pa(pdef_->getSpaceInformation());
    planner->setProblemDefinition(pdef_);
    planners_.push_back(planner);
}

void ompl::tools::ParallelPlan::clearPlanners()
{
    planners_.clear();
}

void ompl::tools::ParallelPlan::clearHybridizationPaths()
{
    phybrid_->clear();
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(double solveTime, bool hybridize)
{
    return solve(solveTime, 1, planners_.size(), hybridize);
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(double solveTime, std::size_t minSolCount, std::size_t maxSolCount, bool hybridize)
{
    return solve(base::timedPlannerTerminationCondition(solveTime, std::min(solveTime / 100.0, 0.1)), minSolCount, maxSolCount, hybridize);
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(const base::PlannerTerminationCondition &ptc, bool hybridize)
{
    return solve(ptc, 1, planners_.size(), hybridize);
}

ompl::base::PlannerStatus ompl::tools::ParallelPlan::solve(const base::PlannerTerminationCondition &ptc, std::size_t minSolCount,
  std::size_t maxSolCount, bool hybridize)
{
    if (!pdef_->getSpaceInformation()->isSetup())
        pdef_->getSpaceInformation()->setup();
    foundSolCount_ = 0;

    time::point start = time::now();
    std::vector<boost::thread*> threads(planners_.size());

    // Decide if we are combining solutions or just taking the first one
    if (hybridize)
        for (std::size_t i = 0 ; i < threads.size() ; ++i)
            threads[i] = new boost::thread(boost::bind(&ParallelPlan::solveMore, this, planners_[i].get(), minSolCount, maxSolCount, &ptc));
    else
        for (std::size_t i = 0 ; i < threads.size() ; ++i)
            threads[i] = new boost::thread(boost::bind(&ParallelPlan::solveOne, this, planners_[i].get(), minSolCount, &ptc));

    for (std::size_t i = 0 ; i < threads.size() ; ++i)
    {
        threads[i]->join();
        delete threads[i];
    }

    if (hybridize)
    {
        if (phybrid_->pathCount() > 1)
            if (const base::PathPtr &hsol = phybrid_->getHybridPath())
            {
                geometric::PathGeometric *pg = static_cast<geometric::PathGeometric*>(hsol.get());
                double difference = 0.0;
                bool approximate = !pdef_->getGoal()->isSatisfied(pg->getStates().back(), &difference);
                pdef_->addSolutionPath(hsol, approximate, difference, phybrid_->getName()); // name this solution after the hybridization algorithm
            }
    }

    if (pdef_->hasSolution())
        OMPL_INFORM("ParallelPlan::solve(): Solution found by one or more threads in %f seconds", time::seconds(time::now() - start));
    else
        OMPL_WARN("ParallelPlan::solve(): Unable to find solution by any of the threads in %f seconds", time::seconds(time::now() - start));

    return base::PlannerStatus(pdef_->hasSolution(), pdef_->hasApproximateSolution());
}

void ompl::tools::ParallelPlan::solveOne(base::Planner *planner, std::size_t minSolCount, const base::PlannerTerminationCondition *ptc)
{
    OMPL_DEBUG("ParallelPlan.solveOne starting planner %s", planner->getName().c_str());

    time::point start = time::now();
    if (planner->solve(*ptc))
    {
        double duration = time::seconds(time::now() - start);
        foundSolCountLock_.lock();
        unsigned int nrSol = ++foundSolCount_;
        foundSolCountLock_.unlock();
        if (nrSol >= minSolCount)
            ptc->terminate();
        OMPL_DEBUG("ParallelPlan.solveOne: Solution found by %s in %lf seconds", planner->getName().c_str(), duration);
    }
}

void ompl::tools::ParallelPlan::solveMore(base::Planner *planner, std::size_t minSolCount, std::size_t maxSolCount,
  const base::PlannerTerminationCondition *ptc)
{
    OMPL_DEBUG("ParallelPlan.solveMore: starting planner %s", planner->getName().c_str());

    time::point start = time::now();
    if (planner->solve(*ptc))
    {
        double duration = time::seconds(time::now() - start);
        foundSolCountLock_.lock();
        unsigned int nrSol = ++foundSolCount_;
        foundSolCountLock_.unlock();

        if (nrSol >= maxSolCount)
            ptc->terminate();

        OMPL_DEBUG("ParallelPlan.solveMore: Solution found by %s in %lf seconds", planner->getName().c_str(), duration);

        const std::vector<base::PlannerSolution> &paths = pdef_->getSolutions();

        boost::mutex::scoped_lock slock(phlock_);
        start = time::now();
        unsigned int attempts = 0;
        for (std::size_t i = 0 ; i < paths.size() ; ++i)
            attempts += phybrid_->recordPath(paths[i].path_, false);

        if (phybrid_->pathCount() >= minSolCount)
            phybrid_->computeHybridPath();

        duration = time::seconds(time::now() - start);
        OMPL_DEBUG("ParallelPlan.solveMore: Spent %f seconds hybridizing %u solution paths (attempted %u connections between paths)", duration,
          (unsigned int)phybrid_->pathCount(), attempts);
    }
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/inc_navier_stokes_stab_base.h"

// GRINS
#include "grins/assembly_context.h"

namespace GRINS
{

  IncompressibleNavierStokesStabilizationBase::IncompressibleNavierStokesStabilizationBase( const std::string& physics_name,
                                                                                const GetPot& input )
    : IncompressibleNavierStokesBase(physics_name,input),
      _stab_helper( input )
  {
    this->read_input_options(input);

    return;
  }

  IncompressibleNavierStokesStabilizationBase::~IncompressibleNavierStokesStabilizationBase()
  {
    return;
  }

  void IncompressibleNavierStokesStabilizationBase::init_context( AssemblyContext& context )
  {
    // First call base class
    IncompressibleNavierStokesBase::init_context(context);

    // We need pressure derivatives
    context.get_element_fe(this->_flow_vars.p_var())->get_dphi();

    // We also need second derivatives, so initialize those.
    context.get_element_fe(this->_flow_vars.u_var())->get_d2phi();

    return;
  }

  void IncompressibleNavierStokesStabilizationBase::init_variables( libMesh::FEMSystem* system )
  {
    // First call base class
    IncompressibleNavierStokesBase::init_variables(system);

    _stab_helper.init(*system);

    return;
  }

} // namespace GRINS
<commit_msg>Thought I'd gotten rid of that read_input_options call.<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/inc_navier_stokes_stab_base.h"

// GRINS
#include "grins/assembly_context.h"

namespace GRINS
{

  IncompressibleNavierStokesStabilizationBase::IncompressibleNavierStokesStabilizationBase( const std::string& physics_name,
                                                                                const GetPot& input )
    : IncompressibleNavierStokesBase(physics_name,input),
      _stab_helper( input )
  {
    return;
  }

  IncompressibleNavierStokesStabilizationBase::~IncompressibleNavierStokesStabilizationBase()
  {
    return;
  }

  void IncompressibleNavierStokesStabilizationBase::init_context( AssemblyContext& context )
  {
    // First call base class
    IncompressibleNavierStokesBase::init_context(context);

    // We need pressure derivatives
    context.get_element_fe(this->_flow_vars.p_var())->get_dphi();

    // We also need second derivatives, so initialize those.
    context.get_element_fe(this->_flow_vars.u_var())->get_d2phi();

    return;
  }

  void IncompressibleNavierStokesStabilizationBase::init_variables( libMesh::FEMSystem* system )
  {
    // First call base class
    IncompressibleNavierStokesBase::init_variables(system);

    _stab_helper.init(*system);

    return;
  }

} // namespace GRINS
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#include "maemoremotecopyfacility.h"

#include "maemoglobal.h"

#include <remotelinux/linuxdeviceconfiguration.h>
#include <utils/ssh/sshconnection.h>
#include <utils/ssh/sshremoteprocessrunner.h>

#include <QtCore/QDir>

using namespace RemoteLinux;
using namespace Utils;

namespace Madde {
namespace Internal {

MaemoRemoteCopyFacility::MaemoRemoteCopyFacility(QObject *parent) :
    QObject(parent), m_isCopying(false), m_copyRunner(0)
{
}

MaemoRemoteCopyFacility::~MaemoRemoteCopyFacility() {}

void MaemoRemoteCopyFacility::copyFiles(const SshConnection::Ptr &connection,
    const LinuxDeviceConfiguration::ConstPtr &devConf,
    const QList<DeployableFile> &deployables, const QString &mountPoint)
{
    Q_ASSERT(connection->state() == SshConnection::Connected);
    Q_ASSERT(!m_isCopying);

    m_devConf = devConf;
    m_deployables = deployables;
    m_mountPoint = mountPoint;

    delete m_copyRunner;
    m_copyRunner = new SshRemoteProcessRunner(connection, this);
    connect(m_copyRunner, SIGNAL(connectionError(Utils::SshError)), SLOT(handleConnectionError()));
    connect(m_copyRunner, SIGNAL(processOutputAvailable(QByteArray)),
        SLOT(handleRemoteStdout(QByteArray)));
    connect(m_copyRunner, SIGNAL(processErrorOutputAvailable(QByteArray)),
        SLOT(handleRemoteStderr(QByteArray)));
    connect(m_copyRunner, SIGNAL(processClosed(int)), SLOT(handleCopyFinished(int)));

    m_isCopying = true;
    copyNextFile();
}

void MaemoRemoteCopyFacility::cancel()
{
    Q_ASSERT(m_isCopying);

    // TODO: Make member as to not waste memory.
    SshRemoteProcessRunner * const killProcess
        = new SshRemoteProcessRunner(m_copyRunner->connection(), this);
    killProcess->run("pkill cp");
    setFinished();
}

void MaemoRemoteCopyFacility::handleConnectionError()
{
    const QString errMsg = m_copyRunner->connection()->errorString();
    setFinished();
    emit finished(tr("Connection failed: %1").arg(errMsg));
}

void MaemoRemoteCopyFacility::handleRemoteStdout(const QByteArray &output)
{
    emit stdoutData(QString::fromUtf8(output));
}

void MaemoRemoteCopyFacility::handleRemoteStderr(const QByteArray &output)
{
    emit stderrData(QString::fromUtf8(output));
}

void MaemoRemoteCopyFacility::handleCopyFinished(int exitStatus)
{
    if (!m_isCopying)
        return;

    if (exitStatus != SshRemoteProcess::ExitedNormally
            || m_copyRunner->process()->exitCode() != 0) {
        setFinished();
        emit finished(tr("Error: Copy command failed."));
    } else {
        emit fileCopied(m_deployables.takeFirst());
        copyNextFile();
    }
}

void MaemoRemoteCopyFacility::copyNextFile()
{
    Q_ASSERT(m_isCopying);

    if (m_deployables.isEmpty()) {
        setFinished();
        emit finished();
        return;
    }

    const DeployableFile &d = m_deployables.first();
    QString sourceFilePath = m_mountPoint;
#ifdef Q_OS_WIN
    const QString localFilePath = QDir::fromNativeSeparators(d.localFilePath);
    sourceFilePath += QLatin1Char('/') + localFilePath.at(0).toLower()
        + localFilePath.mid(2);
#else
    sourceFilePath += d.localFilePath;
#endif

    QString command = QString::fromLatin1("%1 mkdir -p %3 && %1 cp -a %2 %3")
        .arg(MaemoGlobal::remoteSudo(m_devConf->osType(),
            m_copyRunner->connection()->connectionParameters().userName),
            sourceFilePath, d.remoteDir);
    emit progress(tr("Copying file '%1' to directory '%2' on the device...")
        .arg(d.localFilePath, d.remoteDir));
    m_copyRunner->run(command.toUtf8());
}

void MaemoRemoteCopyFacility::setFinished()
{
    disconnect(m_copyRunner, 0, this, 0);
    delete m_copyRunner;
    m_copyRunner = 0;
    m_deployables.clear();
    m_isCopying = false;
}

} // namespace Internal
} // namespace Madde
<commit_msg>Fix warning<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#include "maemoremotecopyfacility.h"

#include "maemoglobal.h"

#include <remotelinux/linuxdeviceconfiguration.h>
#include <utils/ssh/sshconnection.h>
#include <utils/ssh/sshremoteprocessrunner.h>

#include <QtCore/QDir>

using namespace RemoteLinux;
using namespace Utils;

namespace Madde {
namespace Internal {

MaemoRemoteCopyFacility::MaemoRemoteCopyFacility(QObject *parent) :
    QObject(parent), m_copyRunner(0), m_isCopying(false)
{
}

MaemoRemoteCopyFacility::~MaemoRemoteCopyFacility() {}

void MaemoRemoteCopyFacility::copyFiles(const SshConnection::Ptr &connection,
    const LinuxDeviceConfiguration::ConstPtr &devConf,
    const QList<DeployableFile> &deployables, const QString &mountPoint)
{
    Q_ASSERT(connection->state() == SshConnection::Connected);
    Q_ASSERT(!m_isCopying);

    m_devConf = devConf;
    m_deployables = deployables;
    m_mountPoint = mountPoint;

    delete m_copyRunner;
    m_copyRunner = new SshRemoteProcessRunner(connection, this);
    connect(m_copyRunner, SIGNAL(connectionError(Utils::SshError)), SLOT(handleConnectionError()));
    connect(m_copyRunner, SIGNAL(processOutputAvailable(QByteArray)),
        SLOT(handleRemoteStdout(QByteArray)));
    connect(m_copyRunner, SIGNAL(processErrorOutputAvailable(QByteArray)),
        SLOT(handleRemoteStderr(QByteArray)));
    connect(m_copyRunner, SIGNAL(processClosed(int)), SLOT(handleCopyFinished(int)));

    m_isCopying = true;
    copyNextFile();
}

void MaemoRemoteCopyFacility::cancel()
{
    Q_ASSERT(m_isCopying);

    // TODO: Make member as to not waste memory.
    SshRemoteProcessRunner * const killProcess
        = new SshRemoteProcessRunner(m_copyRunner->connection(), this);
    killProcess->run("pkill cp");
    setFinished();
}

void MaemoRemoteCopyFacility::handleConnectionError()
{
    const QString errMsg = m_copyRunner->connection()->errorString();
    setFinished();
    emit finished(tr("Connection failed: %1").arg(errMsg));
}

void MaemoRemoteCopyFacility::handleRemoteStdout(const QByteArray &output)
{
    emit stdoutData(QString::fromUtf8(output));
}

void MaemoRemoteCopyFacility::handleRemoteStderr(const QByteArray &output)
{
    emit stderrData(QString::fromUtf8(output));
}

void MaemoRemoteCopyFacility::handleCopyFinished(int exitStatus)
{
    if (!m_isCopying)
        return;

    if (exitStatus != SshRemoteProcess::ExitedNormally
            || m_copyRunner->process()->exitCode() != 0) {
        setFinished();
        emit finished(tr("Error: Copy command failed."));
    } else {
        emit fileCopied(m_deployables.takeFirst());
        copyNextFile();
    }
}

void MaemoRemoteCopyFacility::copyNextFile()
{
    Q_ASSERT(m_isCopying);

    if (m_deployables.isEmpty()) {
        setFinished();
        emit finished();
        return;
    }

    const DeployableFile &d = m_deployables.first();
    QString sourceFilePath = m_mountPoint;
#ifdef Q_OS_WIN
    const QString localFilePath = QDir::fromNativeSeparators(d.localFilePath);
    sourceFilePath += QLatin1Char('/') + localFilePath.at(0).toLower()
        + localFilePath.mid(2);
#else
    sourceFilePath += d.localFilePath;
#endif

    QString command = QString::fromLatin1("%1 mkdir -p %3 && %1 cp -a %2 %3")
        .arg(MaemoGlobal::remoteSudo(m_devConf->osType(),
            m_copyRunner->connection()->connectionParameters().userName),
            sourceFilePath, d.remoteDir);
    emit progress(tr("Copying file '%1' to directory '%2' on the device...")
        .arg(d.localFilePath, d.remoteDir));
    m_copyRunner->run(command.toUtf8());
}

void MaemoRemoteCopyFacility::setFinished()
{
    disconnect(m_copyRunner, 0, this, 0);
    delete m_copyRunner;
    m_copyRunner = 0;
    m_deployables.clear();
    m_isCopying = false;
}

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


<commit_before>/*
 * prepare_state.cpp
 *
 *  Created on: Jul 20, 2015
 *      Author: zmij
 */

#include <tip/db/pg/detail/extended_query_state.hpp>
#include <tip/db/pg/detail/md5.hpp>
#include <tip/db/pg/detail/basic_connection.hpp>
#include <tip/db/pg/detail/protocol.hpp>
#include <tip/db/pg/detail/result_impl.hpp>

#include <tip/db/pg/log.hpp>

namespace tip {
namespace db {
namespace pg {
namespace detail {

namespace {
/** Local logging facility */
using namespace tip::log;

const std::string LOG_CATEGORY = "PGEQUERY";
logger::event_severity DEFAULT_SEVERITY = logger::TRACE;
local
local_log(logger::event_severity s = DEFAULT_SEVERITY)
{
	return local(LOG_CATEGORY, s);
}

}  // namespace
// For more convenient changing severity, eg local_log(logger::WARNING)
using tip::log::logger;

extended_query_state::extended_query_state(connection_base& conn,
		std::string const& query,
		param_types const& types,
		params_buffer const& params,
		result_callback const& cb,
		query_error_callback const& err)
	: basic_state(conn), query_(query), param_types_(types), params_(params),
	  result_(cb), error_(err), stage_(PARSE)
{
}

bool
extended_query_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	switch (tag) {
		case ready_for_query_tag : {
			if (stage_ == PARSE) {
				stage_ = BIND;
				enter();
			} else if (stage_ == BIND) {
				stage_ = FETCH;
				enter();
			}
			return true;
		}
		case command_complete_tag: {
			conn.pop_state(this);
			conn.state()->handle_message(m);
			return true;
		}
		default:
			break;
	}
	return false;
}

void
extended_query_state::do_enter()
{
	std::string query_hash = "q_" +
			std::string(boost::md5( query_.c_str() ).digest().hex_str_value());
	if (conn.is_prepared(query_hash)) {
		std::string portal_name = "p_" +
				std::string(boost::md5( query_hash.c_str() ).digest().hex_str_value());
		if (stage_ == PARSE) {
			stage_ = BIND;
		}
		if (stage_ == BIND) {
			local_log() << "Bind params";
			// bind params
			conn.push_state(connection_state_ptr(
					new bind_state(conn, query_hash, params_, error_) ));
		} else {
			local_log() << "Execute statement";
			// execute and fetch
			conn.push_state(connection_state_ptr(
					new execute_state(conn, "", result_, error_) ));
		}
	} else {
		// parse
		conn.push_state( connection_state_ptr(
				new parse_state( conn, query_hash, query_, param_types_, error_ ) ) );
	}
}

parse_state::parse_state(connection_base& conn,
		std::string const& query_name,
		std::string const& query,
		extended_query_state::param_types const& types,
		query_error_callback const& err)
	: basic_state(conn), query_name_(query_name), query_(query), param_types_(types), error_(err)
{
}

void
parse_state::do_enter()
{
	{
		local_log() << "Parse query "
				<< (util::MAGENTA | util::BRIGHT)
				<< query_
				<< logger::severity_color();
	}

	{
		message parse(parse_tag);
		parse.write(query_name_);
		parse.write(query_);
		parse.write( (smallint)param_types_.size() );
		for (oids::type::oid_type oid : param_types_) {
			parse.write( (integer)oid );
		}
		conn.send(parse);
	}
	{
		message describe(describe_tag);
		describe.write('S');
		describe.write(query_name_);
		conn.send(describe);
	}
	{
		message sync(sync_tag);
		conn.send(sync);
	}
}

bool
parse_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	switch (tag) {
		case parse_complete_tag : {
			{
				local_log() << "Parse complete";
			}
			conn.set_prepared(query_name_);
			conn.pop_state(this);
			return true;
		}
		case ready_for_query_tag : {
			{
				local_log() << "Ready for query in parse state";
			}
			message m(sync_tag);
			conn.send(m);
			return true;
		}
		default:
			break;
	}
	return false;
}

bind_state::bind_state(connection_base& conn,
		std::string const& query_name,
		params_buffer const& params,
		query_error_callback const& err)
	: basic_state(conn), query_name_(query_name),
	  params_(params)
{
}

void
bind_state::do_enter()
{
	{
		message m(bind_tag);
		m.write(std::string(""));
		m.write(query_name_);
		if (!params_.empty()) {
			local_log() << "Params buffer size " << params_.size();
			auto out = m.output();
			std::copy( params_.begin(), params_.end(), out );
		} else {
			m.write((smallint)0); // parameter format codes
			m.write((smallint)0); // number of parameters
		}
		m.write((smallint)0); // result format codes
		conn.send(m);
	}
	{
		message m(sync_tag);
		conn.send(m);
	}
}

bool
bind_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	switch (tag) {
		case bind_complete_tag: {
			{
				local_log() << "Bind complete";
			}
			conn.pop_state(this);
			return true;
		}
		default:
			break;
	}
	return false;
}

execute_state::execute_state(connection_base& conn,
		std::string const& portal_name,
		result_callback const& cb,
		query_error_callback const& err)
	: fetch_state(conn, cb, err), portal_name_(portal_name),
	  sync_sent_(false), prev_rows_(0)
{
}

void
execute_state::do_enter()
{
	{
		message m(describe_tag);
		m.write('P');
		m.write(portal_name_);
		conn.send(m);
	}
	{
		message m(sync_tag);
		conn.send(m);
	}
}

bool
execute_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	if (fetch_state::do_handle_message(m) && tag != command_complete_tag) {
		return true;
	} else {
		switch (tag) {
			case ready_for_query_tag: {
				if (!complete_) {
					{
						local_log() << "Ready for query in execute state";
					}
					{
						sync_sent_ = false;
						message m(execute_tag);
						m.write(portal_name_);
						m.write((integer)0); // row limit
						conn.send(m);
					}

				}
				return true;
			}
			case command_complete_tag: {
				{
					local_log() << "Command complete in execute state";
				}
				conn.pop_state(this);
				conn.state()->handle_message(m);
				return true;
			}
			default:
				break;
		}
	}
	return false;
}

void
execute_state::on_package_complete(size_t bytes)
{
	fetch_state::on_package_complete(bytes);
	{
		local_log() << "Package complete in execute state";
	}
	if (!result_) {
		message m(sync_tag);
		conn.send(m);
		prev_rows_ = 0;
		local_log() << "Send sync";
	} else if (result_) {
		if (result_->size() == prev_rows_) {
			message m(sync_tag);
			conn.send(m);
			local_log() << "Send sync";
		}
		prev_rows_ = result_->size();
	}
//	if (!complete_ && !sync_sent_) {
//		message m(sync_tag);
//		conn.send(m);
//		sync_sent_ = true;
//	}
}

} /* namespace detail */
} /* namespace pg */
} /* namespace db */
} /* namespace tip */
<commit_msg>Add parameter types to query "name" hash<commit_after>/*
 * prepare_state.cpp
 *
 *  Created on: Jul 20, 2015
 *      Author: zmij
 */

#include <tip/db/pg/detail/extended_query_state.hpp>
#include <tip/db/pg/detail/md5.hpp>
#include <tip/db/pg/detail/basic_connection.hpp>
#include <tip/db/pg/detail/protocol.hpp>
#include <tip/db/pg/detail/result_impl.hpp>

#include <tip/db/pg/log.hpp>

#include <sstream>

namespace tip {
namespace db {
namespace pg {
namespace detail {

namespace {
/** Local logging facility */
using namespace tip::log;

const std::string LOG_CATEGORY = "PGEQUERY";
logger::event_severity DEFAULT_SEVERITY = logger::TRACE;
local
local_log(logger::event_severity s = DEFAULT_SEVERITY)
{
	return local(LOG_CATEGORY, s);
}

}  // namespace
// For more convenient changing severity, eg local_log(logger::WARNING)
using tip::log::logger;

extended_query_state::extended_query_state(connection_base& conn,
		std::string const& query,
		param_types const& types,
		params_buffer const& params,
		result_callback const& cb,
		query_error_callback const& err)
	: basic_state(conn), query_(query), param_types_(types), params_(params),
	  result_(cb), error_(err), stage_(PARSE)
{
}

bool
extended_query_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	switch (tag) {
		case ready_for_query_tag : {
			if (stage_ == PARSE) {
				stage_ = BIND;
				enter();
			} else if (stage_ == BIND) {
				stage_ = FETCH;
				enter();
			}
			return true;
		}
		case command_complete_tag: {
			conn.pop_state(this);
			conn.state()->handle_message(m);
			return true;
		}
		default:
			break;
	}
	return false;
}

void
extended_query_state::do_enter()
{
	std::ostringstream os;
	os << query_ << " {";
	for (auto oid : param_types_) {
		os << oid;
	}
	os << "}";
	std::string query_hash = "q_" +
			std::string(boost::md5( os.str().c_str() ).digest().hex_str_value());
	if (conn.is_prepared(query_hash)) {
		std::string portal_name = "p_" +
				std::string(boost::md5( query_hash.c_str() ).digest().hex_str_value());
		if (stage_ == PARSE) {
			stage_ = BIND;
		}
		if (stage_ == BIND) {
			local_log() << "Bind params";
			// bind params
			conn.push_state(connection_state_ptr(
					new bind_state(conn, query_hash, params_, error_) ));
		} else {
			local_log() << "Execute statement";
			// execute and fetch
			conn.push_state(connection_state_ptr(
					new execute_state(conn, "", result_, error_) ));
		}
	} else {
		// parse
		conn.push_state( connection_state_ptr(
				new parse_state( conn, query_hash, query_, param_types_, error_ ) ) );
	}
}

parse_state::parse_state(connection_base& conn,
		std::string const& query_name,
		std::string const& query,
		extended_query_state::param_types const& types,
		query_error_callback const& err)
	: basic_state(conn), query_name_(query_name), query_(query), param_types_(types), error_(err)
{
}

void
parse_state::do_enter()
{
	{
		local_log() << "Parse query "
				<< (util::MAGENTA | util::BRIGHT)
				<< query_
				<< logger::severity_color();
	}

	{
		message parse(parse_tag);
		parse.write(query_name_);
		parse.write(query_);
		parse.write( (smallint)param_types_.size() );
		for (oids::type::oid_type oid : param_types_) {
			parse.write( (integer)oid );
		}
		conn.send(parse);
	}
	{
		message describe(describe_tag);
		describe.write('S');
		describe.write(query_name_);
		conn.send(describe);
	}
	{
		message sync(sync_tag);
		conn.send(sync);
	}
}

bool
parse_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	switch (tag) {
		case parse_complete_tag : {
			{
				local_log() << "Parse complete";
			}
			conn.set_prepared(query_name_);
			conn.pop_state(this);
			return true;
		}
		case ready_for_query_tag : {
			{
				local_log() << "Ready for query in parse state";
			}
			message m(sync_tag);
			conn.send(m);
			return true;
		}
		default:
			break;
	}
	return false;
}

bind_state::bind_state(connection_base& conn,
		std::string const& query_name,
		params_buffer const& params,
		query_error_callback const& err)
	: basic_state(conn), query_name_(query_name),
	  params_(params)
{
}

void
bind_state::do_enter()
{
	{
		message m(bind_tag);
		m.write(std::string(""));
		m.write(query_name_);
		if (!params_.empty()) {
			local_log() << "Params buffer size " << params_.size();
			auto out = m.output();
			std::copy( params_.begin(), params_.end(), out );
		} else {
			m.write((smallint)0); // parameter format codes
			m.write((smallint)0); // number of parameters
		}
		m.write((smallint)0); // result format codes
		conn.send(m);
	}
	{
		message m(sync_tag);
		conn.send(m);
	}
}

bool
bind_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	switch (tag) {
		case bind_complete_tag: {
			{
				local_log() << "Bind complete";
			}
			conn.pop_state(this);
			return true;
		}
		default:
			break;
	}
	return false;
}

execute_state::execute_state(connection_base& conn,
		std::string const& portal_name,
		result_callback const& cb,
		query_error_callback const& err)
	: fetch_state(conn, cb, err), portal_name_(portal_name),
	  sync_sent_(false), prev_rows_(0)
{
}

void
execute_state::do_enter()
{
	{
		message m(describe_tag);
		m.write('P');
		m.write(portal_name_);
		conn.send(m);
	}
	{
		message m(sync_tag);
		conn.send(m);
	}
}

bool
execute_state::do_handle_message(message_ptr m)
{
	message_tag tag = m->tag();
	if (fetch_state::do_handle_message(m) && tag != command_complete_tag) {
		return true;
	} else {
		switch (tag) {
			case ready_for_query_tag: {
				if (!complete_) {
					{
						local_log() << "Ready for query in execute state";
					}
					{
						sync_sent_ = false;
						message m(execute_tag);
						m.write(portal_name_);
						m.write((integer)0); // row limit
						conn.send(m);
					}

				}
				return true;
			}
			case command_complete_tag: {
				{
					local_log() << "Command complete in execute state";
				}
				conn.pop_state(this);
				conn.state()->handle_message(m);
				return true;
			}
			default:
				break;
		}
	}
	return false;
}

void
execute_state::on_package_complete(size_t bytes)
{
	fetch_state::on_package_complete(bytes);
	{
		local_log() << "Package complete in execute state";
	}
	if (!result_) {
		message m(sync_tag);
		conn.send(m);
		prev_rows_ = 0;
		local_log() << "Send sync";
	} else if (result_) {
		if (result_->size() == prev_rows_) {
			message m(sync_tag);
			conn.send(m);
			local_log() << "Send sync";
		}
		prev_rows_ = result_->size();
	}
//	if (!complete_ && !sync_sent_) {
//		message m(sync_tag);
//		conn.send(m);
//		sync_sent_ = true;
//	}
}

} /* namespace detail */
} /* namespace pg */
} /* namespace db */
} /* namespace tip */
<|endoftext|>