<commit_before>///
/// @file  D4.cpp
/// @brief This is a highly optimized implementation of the D(x, y)
///        formula in Xavier Gourdon's prime counting algorithm. The D
///        formula is very similar to the formula of the hard special
///        leaves in the Deleglise-Rivat algorithm. Hence this
///        implementation is basically identical to S2_hard.cpp except
///        that the bounds have been changed slightly.
///
///        This implementation uses multi-threading with advanced load
///        balancing, it scales well up to a large number of CPU cores
///        because the compute threads are completely independent from
///        each other. This implementation also uses the highly
///        optimized Sieve class and the DFactorTable class which is a
///        compressed lookup table of moebius function values,
///        least prime factors and max prime factors.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <PiTable.hpp>
#include <Sieve.hpp>
#include <LoadBalancer.hpp>
#include <fast_div.hpp>
#include <generate.hpp>
#include <generate_phi.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <print.hpp>

#include "DFactorTable.hpp"

#include <stdint.h>
#include <vector>

using namespace std;
using namespace primecount;

namespace {

/// Compute the contribution of the hard special leaves using a
/// segmented sieve. Each thread processes the interval
/// [low, low + segments * segment_size[.
///
template <typename T, typename DFactorTable, typename Primes>
T D_thread(T x,
           int64_t x_star,
           int64_t xz,
           int64_t y,
           int64_t z,
           int64_t k,
           int64_t low,
           int64_t segments,
           int64_t segment_size,
           DFactorTable& factor,
           PiTable& pi,
           Primes& primes,
           Runtime& runtime)
{
  T sum = 0;
  int64_t pi_sqrtz = pi[isqrt(z)];
  int64_t low1 = max(low, 1);
  int64_t limit = min(low + segments * segment_size, xz + 1);
  int64_t max_b = pi[min3(isqrt(x / low1), isqrt(limit), x_star)];
  int64_t min_b = pi[min(xz / limit, x_star)];
  min_b = max(k, min_b) + 1;

  if (min_b > max_b)
    return 0;

  runtime.init_start();
  Sieve sieve(low, segment_size, max_b);
  auto phi = generate_phi(low, max_b, primes, pi);
  runtime.init_stop();

  // Segmented sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // current segment [low, high[
    int64_t high = min(low + segment_size, limit);
    low1 = max(low, 1);

    // For i < min_b there are no special leaves:
    // low <= x / (primes[i] * m) < high
    sieve.pre_sieve(primes, min_b - 1, low, high);
    int64_t count_low_high = sieve.count((high - 1) - low);
    int64_t b = min_b;

    // For k + 1 <= b <= pi_sqrtz
    // Find all special leaves in the current segment that are
    // composed of a prime and a square free number:
    // low <= x / (primes[b] * m) < high
    for (int64_t end = min(pi_sqrtz, max_b); b <= end; b++)
    {
      int64_t prime = primes[b];
      T xp = x / prime;
      int64_t xp_div_low = min(fast_div(xp, low1), z);
      int64_t xp_div_high = min(fast_div(xp, high), z);
      int64_t min_m = max(xp_div_high, z / prime);
      int64_t max_m = min(x / ipow<T>(prime, 3), xp_div_low);

      if (prime >= max_m)
        goto next_segment;

      min_m = factor.to_index(min_m);
      max_m = factor.to_index(max_m);

      int64_t count = 0;
      int64_t start = 0;

      for (int64_t m = max_m; m > min_m; m--)
      {
        // mu[m] != 0 &&
        // lpf[m] > prime &&
        // mpf[m] <= y
        if (prime < factor.is_leaf(m))
        {
          int64_t xpm = fast_div64(xp, factor.to_number(m));
          int64_t stop = xpm - low;
          count += sieve.count(start, stop, low, high, count, count_low_high);
          start = stop + 1;
          int64_t phi_xpm = phi[b] + count;
          int64_t mu_m = factor.mu(m);
          sum -= mu_m * phi_xpm;
        }
      }

      phi[b] += count_low_high;
      count_low_high -= sieve.cross_off_count(prime, b);
    }

    // For pi_sqrtz < b <= pi_x_star
    // Find all special leaves in the current segment
    // that are composed of 2 primes:
    // low <= x / (primes[b] * primes[l]) < high
    for (; b <= max_b; b++)
    {
      int64_t prime = primes[b];
      T xp = x / prime;
      int64_t xp_div_low = min(fast_div(xp, low1), y);
      int64_t xp_div_high = min(fast_div(xp, high), y);
      int64_t min_m = max(xp_div_high, prime);
      int64_t max_m = min(x / ipow<T>(prime, 3), xp_div_low);

      int64_t l = pi[max_m];
      int64_t count = 0;
      int64_t start = 0;

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t xpq = fast_div64(xp, primes[l]);
        int64_t stop = xpq - low;
        count += sieve.count(start, stop, low, high, count, count_low_high);
        start = stop + 1;
        int64_t phi_xpq = phi[b] + count;
        sum += phi_xpq;
      }

      phi[b] += count_low_high;
      count_low_high -= sieve.cross_off_count(prime, b);
    }

    next_segment:;
  }

  return sum;
}

/// Calculate the contribution of the hard special leaves.
///
/// This is a parallel D(x, y) implementation with advanced load
/// balancing. As most special leaves tend to be in the first segments
/// we start off with a tiny segment size and one segment per thread.
/// After each iteration we dynamically increase the segment size (until
/// it reaches some limit) or the number of segments.
///
/// D(x, y) has been parallelized using an idea devised by Xavier
/// Gourdon. The idea is to make the individual threads completely
/// independent from each other so that no thread depends on values
/// calculated by another thread. The benefit of this approach is that
/// the algorithm will scale well up to a very large number of CPU
/// cores. In order to make the threads independent from each other
/// each thread needs to precompute a lookup table of phi(x, a) values
/// (this is done in D_thread(x, y)) every time the thread starts
/// a new computation.
///
template <typename T, typename DFactorTable, typename Primes>
T D_OpenMP(T x,
           int64_t y,
           int64_t z,
           int64_t k,
           T d_approx,
           Primes& primes,
           DFactorTable& factor,
           int threads)
{
  int64_t xz = x / z;
  int64_t x_star = get_x_star_gourdon(x, y);
  threads = ideal_num_threads(threads, xz);

  PiTable pi(y);
  LoadBalancer loadBalancer(x, xz, d_approx);

  #pragma omp parallel for num_threads(threads)
  for (int i = 0; i < threads; i++)
  {
    int64_t low = 0;
    int64_t segments = 0;
    int64_t segment_size = 0;
    T sum = 0;
    Runtime runtime;

    while (loadBalancer.get_work(&low, &segments, &segment_size, sum, runtime))
    {
      runtime.start();
      // Unsigned integer division is usually slightly
      // faster than signed integer division
      using UT = typename make_unsigned<T>::type;
      sum = D_thread((UT) x, x_star, xz, y, z, k, low, segments, segment_size, factor, pi, primes, runtime);
      runtime.stop();
    }
  }

  T sum = (T) loadBalancer.get_sum();

  return sum;
}

} // namespace

namespace primecount {

int64_t D(int64_t x,
          int64_t y,
          int64_t z,
          int64_t k,
          int64_t d_approx,
          int threads)
{
  print("");
  print("=== D(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  DFactorTable<uint16_t> factor(y, z, threads);
  auto primes = generate_primes<int32_t>(y);
  int64_t sum = D_OpenMP(x, y, z, k, d_approx, primes, factor, threads);

  print("D", sum, time);
  return sum;
}

#ifdef HAVE_INT128_T

int128_t D(int128_t x,
           int64_t y,
           int64_t z,
           int64_t k,
           int128_t d_approx,
           int threads)
{
  print("");
  print("=== D(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  int128_t sum;

  // uses less memory
  if (z <= DFactorTable<uint16_t>::max())
  {
    DFactorTable<uint16_t> factor(y, z, threads);
    auto primes = generate_primes<uint32_t>(y);
    sum = D_OpenMP(x, y, z, k, d_approx, primes, factor, threads);
  }
  else
  {
    DFactorTable<uint32_t> factor(y, z, threads);
    auto primes = generate_primes<int64_t>(y);
    sum = D_OpenMP(x, y, z, k, d_approx, primes, factor, threads);
  }

  print("D", sum, time);
  return sum;
}

#endif

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file  D4.cpp
/// @brief This is a highly optimized implementation of the D(x, y)
///        formula in Xavier Gourdon's prime counting algorithm. The D
///        formula is very similar to the formula of the hard special
///        leaves in the Deleglise-Rivat algorithm. Hence this
///        implementation is basically identical to S2_hard.cpp except
///        that the bounds have been changed slightly.
///
///        This implementation uses multi-threading with advanced load
///        balancing, it scales well up to a large number of CPU cores
///        because the compute threads are completely independent from
///        each other. This implementation also uses the highly
///        optimized Sieve class and the DFactorTable class which is a
///        compressed lookup table of moebius function values,
///        least prime factors and max prime factors.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <PiTable.hpp>
#include <Sieve.hpp>
#include <LoadBalancer.hpp>
#include <fast_div.hpp>
#include <generate.hpp>
#include <generate_phi.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <print.hpp>

#include "DFactorTable.hpp"

#include <stdint.h>
#include <vector>

using namespace std;
using namespace primecount;

namespace {

/// Compute the contribution of the hard special leaves using a
/// segmented sieve. Each thread processes the interval
/// [low, low + segments * segment_size[.
///
template <typename T, typename DFactorTable, typename Primes>
T D_thread(T x,
           int64_t x_star,
           int64_t xz,
           int64_t y,
           int64_t z,
           int64_t k,
           int64_t low,
           int64_t segments,
           int64_t segment_size,
           DFactorTable& factor,
           PiTable& pi,
           Primes& primes,
           Runtime& runtime)
{
  T sum = 0;
  int64_t pi_sqrtz = pi[isqrt(z)];
  int64_t low1 = max(low, 1);
  int64_t limit = min(low + segments * segment_size, xz + 1);
  int64_t max_b = pi[min3(isqrt(x / low1), isqrt(limit), x_star)];
  int64_t min_b = pi[min(xz / limit, x_star)];
  min_b = max(k, min_b) + 1;

  if (min_b > max_b)
    return 0;

  runtime.init_start();
  Sieve sieve(low, segment_size, max_b);
  auto phi = generate_phi(low, max_b, primes, pi);
  runtime.init_stop();

  // Segmented sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // current segment [low, high[
    int64_t high = min(low + segment_size, limit);
    low1 = max(low, 1);

    // For i < min_b there are no special leaves:
    // low <= x / (primes[i] * m) < high
    sieve.pre_sieve(primes, min_b - 1, low, high);
    int64_t count_low_high = sieve.count((high - 1) - low);
    int64_t b = min_b;

    // For k + 1 <= b <= pi_sqrtz
    // Find all special leaves in the current segment that are
    // composed of a prime and a square free number:
    // low <= x / (primes[b] * m) < high
    for (int64_t end = min(pi_sqrtz, max_b); b <= end; b++)
    {
      int64_t prime = primes[b];
      T xp = x / prime;
      int64_t xp_div_low = min(fast_div(xp, low1), z);
      int64_t xp_div_high = min(fast_div(xp, high), z);
      int64_t min_m = max(xp_div_high, z / prime);
      int64_t max_m = min(x / ipow<T>(prime, 3), xp_div_low);

      if (prime >= max_m)
        goto next_segment;

      min_m = factor.to_index(min_m);
      max_m = factor.to_index(max_m);

      int64_t count = 0;
      int64_t start = 0;

      for (int64_t m = max_m; m > min_m; m--)
      {
        // mu[m] != 0 &&
        // lpf[m] > prime &&
        // mpf[m] <= y
        if (prime < factor.is_leaf(m))
        {
          int64_t xpm = fast_div64(xp, factor.to_number(m));
          int64_t stop = xpm - low;
          count += sieve.count(start, stop, low, high, count, count_low_high);
          start = stop + 1;
          int64_t phi_xpm = phi[b] + count;
          int64_t mu_m = factor.mu(m);
          sum -= mu_m * phi_xpm;
        }
      }

      phi[b] += count_low_high;
      count_low_high -= sieve.cross_off_count(prime, b);
    }

    // For pi_sqrtz < b <= pi_x_star
    // Find all special leaves in the current segment
    // that are composed of 2 primes:
    // low <= x / (primes[b] * primes[l]) < high
    for (; b <= max_b; b++)
    {
      int64_t prime = primes[b];
      T xp = x / prime;
      int64_t xp_div_low = min(fast_div(xp, low1), y);
      int64_t xp_div_high = min(fast_div(xp, high), y);
      int64_t min_m = max(xp_div_high, prime);
      int64_t max_m = min(x / ipow<T>(prime, 3), xp_div_low);
      int64_t l = pi[max_m];
      int64_t count = 0;
      int64_t start = 0;

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t xpq = fast_div64(xp, primes[l]);
        int64_t stop = xpq - low;
        count += sieve.count(start, stop, low, high, count, count_low_high);
        start = stop + 1;
        int64_t phi_xpq = phi[b] + count;
        sum += phi_xpq;
      }

      phi[b] += count_low_high;
      count_low_high -= sieve.cross_off_count(prime, b);
    }

    next_segment:;
  }

  return sum;
}

/// Calculate the contribution of the hard special leaves.
///
/// This is a parallel D(x, y) implementation with advanced load
/// balancing. As most special leaves tend to be in the first segments
/// we start off with a tiny segment size and one segment per thread.
/// After each iteration we dynamically increase the segment size (until
/// it reaches some limit) or the number of segments.
///
/// D(x, y) has been parallelized using an idea devised by Xavier
/// Gourdon. The idea is to make the individual threads completely
/// independent from each other so that no thread depends on values
/// calculated by another thread. The benefit of this approach is that
/// the algorithm will scale well up to a very large number of CPU
/// cores. In order to make the threads independent from each other
/// each thread needs to precompute a lookup table of phi(x, a) values
/// (this is done in D_thread(x, y)) every time the thread starts
/// a new computation.
///
template <typename T, typename DFactorTable, typename Primes>
T D_OpenMP(T x,
           int64_t y,
           int64_t z,
           int64_t k,
           T d_approx,
           Primes& primes,
           DFactorTable& factor,
           int threads)
{
  int64_t xz = x / z;
  int64_t x_star = get_x_star_gourdon(x, y);
  threads = ideal_num_threads(threads, xz);

  PiTable pi(y);
  LoadBalancer loadBalancer(x, xz, d_approx);

  #pragma omp parallel for num_threads(threads)
  for (int i = 0; i < threads; i++)
  {
    int64_t low = 0;
    int64_t segments = 0;
    int64_t segment_size = 0;
    T sum = 0;
    Runtime runtime;

    while (loadBalancer.get_work(&low, &segments, &segment_size, sum, runtime))
    {
      runtime.start();
      // Unsigned integer division is usually slightly
      // faster than signed integer division
      using UT = typename make_unsigned<T>::type;
      sum = D_thread((UT) x, x_star, xz, y, z, k, low, segments, segment_size, factor, pi, primes, runtime);
      runtime.stop();
    }
  }

  T sum = (T) loadBalancer.get_sum();

  return sum;
}

} // namespace

namespace primecount {

int64_t D(int64_t x,
          int64_t y,
          int64_t z,
          int64_t k,
          int64_t d_approx,
          int threads)
{
  print("");
  print("=== D(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  DFactorTable<uint16_t> factor(y, z, threads);
  auto primes = generate_primes<int32_t>(y);
  int64_t sum = D_OpenMP(x, y, z, k, d_approx, primes, factor, threads);

  print("D", sum, time);
  return sum;
}

#ifdef HAVE_INT128_T

int128_t D(int128_t x,
           int64_t y,
           int64_t z,
           int64_t k,
           int128_t d_approx,
           int threads)
{
  print("");
  print("=== D(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  int128_t sum;

  // uses less memory
  if (z <= DFactorTable<uint16_t>::max())
  {
    DFactorTable<uint16_t> factor(y, z, threads);
    auto primes = generate_primes<uint32_t>(y);
    sum = D_OpenMP(x, y, z, k, d_approx, primes, factor, threads);
  }
  else
  {
    DFactorTable<uint32_t> factor(y, z, threads);
    auto primes = generate_primes<int64_t>(y);
    sum = D_OpenMP(x, y, z, k, d_approx, primes, factor, threads);
  }

  print("D", sum, time);
  return sum;
}

#endif

} // namespace
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include "config.h"

#if HAVE_ALUGRID

#include <dune/grid/alugrid.hh>

#include "../problems/ESV2007.hh"
#include "../eocexpectations.hh"

namespace Dune {
namespace GDT {
namespace Test {

template <bool anything>
class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, conforming>, double, 1>,
                                    LinearElliptic::ChooseDiscretizer::cg, 1, anything>
    : public internal::LinearEllipticEocExpectationsBase<1>
{
  typedef LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, conforming>, double, 1> TestCaseType;

public:
  static std::vector<double> results(const TestCaseType& /*test_case*/, const std::string type)
  {
    if (type == "L2")
      return {3.82e-02, 9.64e-03, 2.42e-03, 6.04e-04};
    else if (type == "H1_semi" || type == "energy")
      return {1.84e-01, 9.24e-02, 4.63e-02, 2.31e-02};
    else
      EXPECT_TRUE(false) << "test results missing for type: " << type;
    return {};
  } // ... results(...)
}; // LinearEllipticEocExpectations

template <bool anything>
class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, nonconforming>, double, 1>,
                                    LinearElliptic::ChooseDiscretizer::cg, 1, anything>
    : public internal::LinearEllipticEocExpectationsBase<1>
{
  typedef LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, nonconforming>, double, 1> TestCaseType;

public:
  static std::vector<double> results(const TestCaseType& /*test_case*/, const std::string type)
  {
    if (type == "L2")
      return {1.08e-02, 2.70e-03, 6.76e-04, 1.69e-04};
    else if (type == "H1_semi" || type == "energy")
      return {9.79e-02, 4.91e-02, 2.45e-02, 1.23e-02};
    else
      EXPECT_TRUE(false) << "test results missing for type: " << type;
    return {};
  } // ... results(...)
}; // LinearEllipticEocExpectations

template class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, conforming>, double,
                                                                             1>,
                                             LinearElliptic::ChooseDiscretizer::cg, 1>;
template class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, nonconforming>,
                                                                             double, 1>,
                                             LinearElliptic::ChooseDiscretizer::cg, 1>;

} // namespace Test
} // namespace GDT
} // namespace Dune

#endif // HAVE_ALUGRID
<commit_msg>[linearelliptic.cg...] update expected results<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include "config.h"

#if HAVE_ALUGRID

#include <dune/grid/alugrid.hh>

#include "../problems/ESV2007.hh"
#include "../eocexpectations.hh"

namespace Dune {
namespace GDT {
namespace Test {

template <bool anything>
class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, conforming>, double, 1>,
                                    LinearElliptic::ChooseDiscretizer::cg, 1, anything>
    : public internal::LinearEllipticEocExpectationsBase<1>
{
  typedef LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, conforming>, double, 1> TestCaseType;

public:
  static std::vector<double> results(const TestCaseType& /*test_case*/, const std::string type)
  {
    if (type == "L2")
      return {3.82e-02, 9.64e-03, 2.42e-03, 6.04e-04};
    else if (type == "H1_semi" || type == "energy")
      return {1.84e-01, 9.24e-02, 4.63e-02, 2.31e-02};
    else
      EXPECT_TRUE(false) << "test results missing for type: " << type;
    return {};
  } // ... results(...)
}; // LinearEllipticEocExpectations

template <bool anything>
class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, nonconforming>, double, 1>,
                                    LinearElliptic::ChooseDiscretizer::cg, 1, anything>
    : public internal::LinearEllipticEocExpectationsBase<1>
{
  typedef LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, nonconforming>, double, 1> TestCaseType;

public:
  static std::vector<double> results(const TestCaseType& /*test_case*/, const std::string type)
  {
    if (type == "L2")
      return {4.22e-02, 1.08e-02, 2.70e-03, 6.76e-04};
    else if (type == "H1_semi" || type == "energy")
      return {1.94e-01, 9.79e-02, 4.91e-02, 2.45e-02};
    else
      EXPECT_TRUE(false) << "test results missing for type: " << type;
    return {};
  } // ... results(...)
}; // LinearEllipticEocExpectations

template class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, conforming>, double,
                                                                             1>,
                                             LinearElliptic::ChooseDiscretizer::cg, 1>;
template class LinearEllipticEocExpectations<LinearElliptic::ESV2007TestCase<ALUGrid<2, 2, simplex, nonconforming>,
                                                                             double, 1>,
                                             LinearElliptic::ChooseDiscretizer::cg, 1>;

} // namespace Test
} // namespace GDT
} // namespace Dune

#endif // HAVE_ALUGRID
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006,2007,2008,2009,2010,2011,2012 Olly Betts
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "length.h"

std::string encode_length(size_t len)
{
	std::string result;
	if (len < 255) {
		result += static_cast<unsigned char>(len);
	} else {
		result += '\xff';
		len -= 255;
		while (true) {
			unsigned char b = static_cast<unsigned char>(len & 0x7f);
			len >>= 7;
			if (!len) {
				result += (b | static_cast<unsigned char>(0x80));
				break;
			}
			result += b;
		}
	}
	return result;
}

size_t
decode_length(const char ** p, const char *end, bool check_remaining)
{
	const char *pos = *p;
	if (pos == end) {
		return -1;
	}
	size_t len = static_cast<unsigned char>(*pos++);
	if (len == 0xff) {
		len = 0;
		unsigned char ch;
		int shift = 0;
		do {
			if (*p == end || shift > 28)
				return -1;
			ch = *pos++;
			len |= size_t(ch & 0x7f) << shift;
			shift += 7;
		} while ((ch & 0x80) == 0);
		len += 255;
	}
	if (check_remaining && len > size_t(end - *p)) {
		return -1;
	}
	*p = pos;
	return len;
}<commit_msg>Fixed decode_length() to really check against current walking position<commit_after>/*
 * Copyright (C) 2006,2007,2008,2009,2010,2011,2012 Olly Betts
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "length.h"

std::string
encode_length(size_t len)
{
	std::string result;
	if (len < 255) {
		result += static_cast<unsigned char>(len);
	} else {
		result += '\xff';
		len -= 255;
		while (true) {
			unsigned char b = static_cast<unsigned char>(len & 0x7f);
			len >>= 7;
			if (!len) {
				result += (b | static_cast<unsigned char>(0x80));
				break;
			}
			result += b;
		}
	}
	return result;
}

size_t
decode_length(const char ** p, const char *end, bool check_remaining)
{
	const char *pos = *p;
	if (pos == end) {
		return -1;
	}
	size_t len = static_cast<unsigned char>(*pos++);
	if (len == 0xff) {
		len = 0;
		unsigned char ch;
		int shift = 0;
		do {
			if (pos == end || shift > 28)
				return -1;
			ch = *pos++;
			len |= size_t(ch & 0x7f) << shift;
			shift += 7;
		} while ((ch & 0x80) == 0);
		len += 255;
	}
	if (check_remaining && len > size_t(end - pos)) {
		return -1;
	}
	*p = pos;
	return len;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Bram van der Kroef
 *
 * This file is part of LESS CSS Compiler.
 *
 * LESS CSS Compiler is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LESS CSS Compiler 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LESS CSS Compiler.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Bram van der Kroef <bram@vanderkroef.net>
 */

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <getopt.h>

#include "LessTokenizer.h"
#include "LessParser.h"
#include "CssWriter.h"
#include "CssPrettyWriter.h"
#include "Stylesheet.h"
#include "IOException.h"
#include "LessStylesheet.h"

#include <config.h>

#ifdef WITH_LIBGLOG
#include <glog/logging.h>
#endif

using namespace std;

/**
 * /main Less CSS compiler, implemented in C++.
 *
 */

void usage () {
  cout <<
    "Usage: lessc [OPTION]... [FILE]\n"
    "\n"
    "   FILE				Less source file. If not given, source \
is read from stdin.\n"
    "   -h, --help			Show this message and exit.\n"
    "       --version		Print the program name and version.\n"
    "\n"
    "   -o, --output=<FILE>		Send output to FILE\n"
    "   -f, --format			Format output CSS with newlines and \
indentation. By default the output is unformatted.\n"
    "\n"
    "   -m, --source-map=[FILE]	Generate a source map.\n"
    "       --source-map-rootpath=<PATH>   PATH is prepended to the \
source file references in the source map, and also to the source map \
reference in the css output. \n"
    "       --source-map-basepath=<PATH>   PATH is removed from the \
source file references in the source map, and also from the source \
map reference in the css output.\n"
    "\n"
    "   -v, --verbose=<LEVEL>	Output log data for debugging. LEVEL is \
a number in the range 1-3 that defines granularity.\n"
    "\n"
    "Example:\n"
    "   lessc in.less -o out.css\n"
    "\n"
    "Report bugs to: " PACKAGE_BUGREPORT "\n"
    PACKAGE_NAME " home page: <" PACKAGE_URL ">\n";
}

void version () {
  cout <<
    PACKAGE_STRING "\n"
    "Copyright 2012 Bram van der Kroef\n"
    "License GPLv3+: GNU GPL version 3 or later \
<http://gnu.org/licenses/gpl.html>\n"
    "This is free software: you are free to change and redistribute it.\n"
    "There is NO WARRANTY, to the extent permitted by law.\n";
}

bool parseInput(LessStylesheet &stylesheet,
                istream &in,
                const char* source,
                std::list<const char*> &sources){
  std::list<const char*>::iterator i;

  LessTokenizer tokenizer(in, source);
  LessParser parser(tokenizer, sources);

  try{
    parser.parseStylesheet(stylesheet);
  } catch(ParseException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#else
    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#endif

    return false;
  } catch(ValueException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Error: " << e->what();
#else
    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Error: " << e->what();
#endif

  } catch(exception* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << " Error: " << e->what();
#else
    cerr << " Error: " << e->what();
#endif
    return false;
  }
#ifdef WITH_LIBGLOG
  VLOG(1) << "Source files: ";
  for(i = sources.begin(); i != sources.end(); i++) {
    VLOG(1) << (*i);
  }
#endif
  return true;
}
void writeOutput (LessStylesheet &stylesheet,
                  CssWriter &writer) {
  Stylesheet css;
  ProcessingContext context;

  try{
    stylesheet.process(css, context);

  } catch(ParseException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#else
    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#endif

    return;
  } catch(exception* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << "Error: " << e->what();
#else
    cerr << "Error: " << e->what();
#endif
    return;
  }

  css.write(writer);
}

int main(int argc, char * argv[]){
  istream* in = &cin;
  ostream* out = &cout;
  bool formatoutput = false;
  char* source = NULL;
  string output = "-";
  LessStylesheet stylesheet;
  std::list<const char*> sources;
  CssWriter* writer;

  std::string sourcemap_file = "";
  ostream* sourcemap_s = NULL;
  SourceMapWriter* sourcemap = NULL;
  const char* sourcemap_rootpath = NULL;
  const char* sourcemap_basepath = NULL;

  static struct option long_options[] = {
    {"version",    no_argument,       0, 1},
    {"help",       no_argument,       0, 'h'},
    {"output",     required_argument, 0, 'o'},
    {"format",     no_argument,       0, 'f'},
    {"verbose",    required_argument, 0, 'v'},
    {"source-map", optional_argument, 0, 'm'},
    {"source-map-rootpath", required_argument, 0, 2},
    {"source-map-basepath", required_argument, 0, 3},
    {0,0,0,0}
  };

#ifdef WITH_LIBGLOG
  FLAGS_logtostderr = 1;
  google::InitGoogleLogging(argv[0]);
  VLOG(1) << "Start.";
#endif

  try {
    int c, option_index;
#ifdef WITH_LIBGLOG
    VLOG(3) << "argc: " << argc;
#endif

    while((c = getopt_long(argc, argv, ":o:hfv:m::", long_options, &option_index)) != -1) {
      switch (c) {
      case 1:
        version();
        return 0;
      case 'h':
        usage();
        return 0;
      case 'o':
        output = optarg;
        out = new ofstream(optarg);
        break;
      case 'f':
        formatoutput = true;
        break;
      case 'v':
#ifdef WITH_LIBGLOG
        FLAGS_v = atoi(optarg);
#else
        std::cerr << "Warning: -v flag not supported: lessc has to be compiled with libglog.\n";
#endif
        break;
      case 'm':
        if (optarg)
          sourcemap_file = optarg;
        else
          sourcemap_file = "-";
        break;

      case 2:
        sourcemap_rootpath = optarg;
        break;
      case 3:
        sourcemap_basepath = optarg;
        break;
      }
    }

    if(argc - optind >= 1){
#ifdef WITH_LIBGLOG
      VLOG(1) << argv[optind];
#endif

      source = new char[std::strlen(argv[optind]) + 1];
      std::strcpy(source, argv[optind]);

      in = new ifstream(source);
      if (in->fail() || in->bad())
        throw new IOException("Error opening file");

    } else if (sourcemap_file == "-") {
      throw new IOException("source-map option requires that \
a file name is specified for either the source map or the less \
source.");
    } else {
      source = new char[2];
      std::strcpy(source, "-");
    }

    if (sourcemap_file == "-") {
      sourcemap_file = source;
      sourcemap_file += ".map";
    }

    sources.push_back(source);

    if (parseInput(stylesheet, *in, source, sources)) {
      if (sourcemap_file != "") {
#ifdef WITH_LIBGLOG
        VLOG(1) << "sourcemap: " << sourcemap_file;
#endif
        sourcemap_s = new ofstream(sourcemap_file.c_str());
        sourcemap = new SourceMapWriter(*sourcemap_s, sources, output.c_str(),
                                        sourcemap_rootpath,
                                        sourcemap_basepath);

        writer = formatoutput ? new CssPrettyWriter(*out, *sourcemap) :
          new CssWriter(*out, *sourcemap);
      } else {
        writer = formatoutput ? new CssPrettyWriter(*out) :
          new CssWriter(*out);
      }

      writeOutput(stylesheet, *writer);

      if (sourcemap != NULL) {
        if (sourcemap_basepath != NULL &&
            sourcemap_file.compare(0, std::strlen(sourcemap_basepath),
                                   sourcemap_basepath) == 0) {
          sourcemap_file.erase(0, std::strlen(sourcemap_basepath));
        }
        if (sourcemap_rootpath != NULL)
          sourcemap_file.insert(0, sourcemap_rootpath);

        writer->writeSourceMapUrl(sourcemap_file.c_str());
        sourcemap->close();
        delete sourcemap;
        if (sourcemap_s != NULL)
          delete sourcemap_s;
      }

      delete writer;
      *out << endl;
    } else
      return 1;
    delete source;

  } catch (IOException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << " Error: " << e->what();
#else
    cerr << " Error: " << e->what();
#endif
    return 1;
  }

  return 0;
}

<commit_msg>Put the ValueException catching in the right place.<commit_after>/*
 * Copyright 2012 Bram van der Kroef
 *
 * This file is part of LESS CSS Compiler.
 *
 * LESS CSS Compiler is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LESS CSS Compiler 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LESS CSS Compiler.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Bram van der Kroef <bram@vanderkroef.net>
 */

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <getopt.h>

#include "LessTokenizer.h"
#include "LessParser.h"
#include "CssWriter.h"
#include "CssPrettyWriter.h"
#include "Stylesheet.h"
#include "IOException.h"
#include "LessStylesheet.h"

#include <config.h>

#ifdef WITH_LIBGLOG
#include <glog/logging.h>
#endif

using namespace std;

/**
 * /main Less CSS compiler, implemented in C++.
 *
 */

void usage () {
  cout <<
    "Usage: lessc [OPTION]... [FILE]\n"
    "\n"
    "   FILE				Less source file. If not given, source \
is read from stdin.\n"
    "   -h, --help			Show this message and exit.\n"
    "       --version		Print the program name and version.\n"
    "\n"
    "   -o, --output=<FILE>		Send output to FILE\n"
    "   -f, --format			Format output CSS with newlines and \
indentation. By default the output is unformatted.\n"
    "\n"
    "   -m, --source-map=[FILE]	Generate a source map.\n"
    "       --source-map-rootpath=<PATH>   PATH is prepended to the \
source file references in the source map, and also to the source map \
reference in the css output. \n"
    "       --source-map-basepath=<PATH>   PATH is removed from the \
source file references in the source map, and also from the source \
map reference in the css output.\n"
    "\n"
    "   -v, --verbose=<LEVEL>	Output log data for debugging. LEVEL is \
a number in the range 1-3 that defines granularity.\n"
    "\n"
    "Example:\n"
    "   lessc in.less -o out.css\n"
    "\n"
    "Report bugs to: " PACKAGE_BUGREPORT "\n"
    PACKAGE_NAME " home page: <" PACKAGE_URL ">\n";
}

void version () {
  cout <<
    PACKAGE_STRING "\n"
    "Copyright 2012 Bram van der Kroef\n"
    "License GPLv3+: GNU GPL version 3 or later \
<http://gnu.org/licenses/gpl.html>\n"
    "This is free software: you are free to change and redistribute it.\n"
    "There is NO WARRANTY, to the extent permitted by law.\n";
}

bool parseInput(LessStylesheet &stylesheet,
                istream &in,
                const char* source,
                std::list<const char*> &sources){
  std::list<const char*>::iterator i;

  LessTokenizer tokenizer(in, source);
  LessParser parser(tokenizer, sources);

  try{
    parser.parseStylesheet(stylesheet);
  } catch(ParseException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#else
    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#endif

    return false;
  } catch(exception* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << " Error: " << e->what();
#else
    cerr << " Error: " << e->what();
#endif
    return false;
  }
#ifdef WITH_LIBGLOG
  VLOG(1) << "Source files: ";
  for(i = sources.begin(); i != sources.end(); i++) {
    VLOG(1) << (*i);
  }
#endif
  return true;
}
void writeOutput (LessStylesheet &stylesheet,
                  CssWriter &writer) {
  Stylesheet css;
  ProcessingContext context;

  try{
    stylesheet.process(css, context);

  } catch(ParseException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#else
    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what();
#endif

    return;

  } catch(ValueException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Error: " << e->what();
#else
    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Error: " << e->what();
#endif

    return;
  } catch(exception* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << "Error: " << e->what();
#else
    cerr << "Error: " << e->what();
#endif
    return;
  }

  css.write(writer);
}

int main(int argc, char * argv[]){
  istream* in = &cin;
  ostream* out = &cout;
  bool formatoutput = false;
  char* source = NULL;
  string output = "-";
  LessStylesheet stylesheet;
  std::list<const char*> sources;
  CssWriter* writer;

  std::string sourcemap_file = "";
  ostream* sourcemap_s = NULL;
  SourceMapWriter* sourcemap = NULL;
  const char* sourcemap_rootpath = NULL;
  const char* sourcemap_basepath = NULL;

  static struct option long_options[] = {
    {"version",    no_argument,       0, 1},
    {"help",       no_argument,       0, 'h'},
    {"output",     required_argument, 0, 'o'},
    {"format",     no_argument,       0, 'f'},
    {"verbose",    required_argument, 0, 'v'},
    {"source-map", optional_argument, 0, 'm'},
    {"source-map-rootpath", required_argument, 0, 2},
    {"source-map-basepath", required_argument, 0, 3},
    {0,0,0,0}
  };

#ifdef WITH_LIBGLOG
  FLAGS_logtostderr = 1;
  google::InitGoogleLogging(argv[0]);
  VLOG(1) << "Start.";
#endif

  try {
    int c, option_index;
#ifdef WITH_LIBGLOG
    VLOG(3) << "argc: " << argc;
#endif

    while((c = getopt_long(argc, argv, ":o:hfv:m::", long_options, &option_index)) != -1) {
      switch (c) {
      case 1:
        version();
        return 0;
      case 'h':
        usage();
        return 0;
      case 'o':
        output = optarg;
        out = new ofstream(optarg);
        break;
      case 'f':
        formatoutput = true;
        break;
      case 'v':
#ifdef WITH_LIBGLOG
        FLAGS_v = atoi(optarg);
#else
        std::cerr << "Warning: -v flag not supported: lessc has to be compiled with libglog.\n";
#endif
        break;
      case 'm':
        if (optarg)
          sourcemap_file = optarg;
        else
          sourcemap_file = "-";
        break;

      case 2:
        sourcemap_rootpath = optarg;
        break;
      case 3:
        sourcemap_basepath = optarg;
        break;
      }
    }

    if(argc - optind >= 1){
#ifdef WITH_LIBGLOG
      VLOG(1) << argv[optind];
#endif

      source = new char[std::strlen(argv[optind]) + 1];
      std::strcpy(source, argv[optind]);

      in = new ifstream(source);
      if (in->fail() || in->bad())
        throw new IOException("Error opening file");

    } else if (sourcemap_file == "-") {
      throw new IOException("source-map option requires that \
a file name is specified for either the source map or the less \
source.");
    } else {
      source = new char[2];
      std::strcpy(source, "-");
    }

    if (sourcemap_file == "-") {
      sourcemap_file = source;
      sourcemap_file += ".map";
    }

    sources.push_back(source);

    if (parseInput(stylesheet, *in, source, sources)) {
      if (sourcemap_file != "") {
#ifdef WITH_LIBGLOG
        VLOG(1) << "sourcemap: " << sourcemap_file;
#endif
        sourcemap_s = new ofstream(sourcemap_file.c_str());
        sourcemap = new SourceMapWriter(*sourcemap_s, sources, output.c_str(),
                                        sourcemap_rootpath,
                                        sourcemap_basepath);

        writer = formatoutput ? new CssPrettyWriter(*out, *sourcemap) :
          new CssWriter(*out, *sourcemap);
      } else {
        writer = formatoutput ? new CssPrettyWriter(*out) :
          new CssWriter(*out);
      }

      writeOutput(stylesheet, *writer);

      if (sourcemap != NULL) {
        if (sourcemap_basepath != NULL &&
            sourcemap_file.compare(0, std::strlen(sourcemap_basepath),
                                   sourcemap_basepath) == 0) {
          sourcemap_file.erase(0, std::strlen(sourcemap_basepath));
        }
        if (sourcemap_rootpath != NULL)
          sourcemap_file.insert(0, sourcemap_rootpath);

        writer->writeSourceMapUrl(sourcemap_file.c_str());
        sourcemap->close();
        delete sourcemap;
        if (sourcemap_s != NULL)
          delete sourcemap_s;
      }

      delete writer;
      *out << endl;
    } else
      return 1;
    delete source;

  } catch (IOException* e) {
#ifdef WITH_LIBGLOG
    LOG(ERROR) << " Error: " << e->what();
#else
    cerr << " Error: " << e->what();
#endif
    return 1;
  }

  return 0;
}

<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <vespa/filedistribution/common/logfwd.h>

#include <stdarg.h>
#include <iostream>
#include <boost/scoped_array.hpp>
#include <stdio.h>

void filedistribution::logfwd::log_forward(LogLevel level, const char* file, int line, const char* fmt, ...)
{
    if (level == debug || level == info)
        return;

    const size_t maxSize(0x8000);
    boost::scoped_array<char> payload(new char[maxSize]);

    va_list args;
    va_start(args, fmt);
    vsnprintf(payload.get(), maxSize, fmt, args);
    va_end(args);

    std::cerr <<"Error: " <<payload.get() <<" File: " <<file <<" Line: " <<line <<std::endl;
}
<commit_msg>boost::scoped_array -> std::vector<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <vespa/filedistribution/common/logfwd.h>

#include <stdarg.h>
#include <iostream>
#include <stdio.h>

void filedistribution::logfwd::log_forward(LogLevel level, const char* file, int line, const char* fmt, ...)
{
    if (level == debug || level == info)
        return;

    const size_t maxSize(0x8000);
    std::vector<char> payload(maxSize);
    char * buf = &payload[0];

    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, maxSize, fmt, args);
    va_end(args);

    std::cerr <<"Error: " << buf <<" File: " <<file <<" Line: " <<line <<std::endl;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011, Peter Thorson. 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 WebSocket++ Project 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 PETER THORSON 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.
 *
 */

#ifndef WSPERF_CASE__AUTOBAHN_HPP
#define WSPERF_CASE__AUTOBAHN_HPP

#include "case.hpp"

namespace wsperf {

// test class for 9.1.* and 9.2.*
class test_9_1_X : public case_handler {
public:
    test_9_1_X(int minor, int subtest)
    : m_minor(minor),
    m_subtest(subtest)
    {
        // needs more C++11 intializer lists =(
        m_test_sizes[0] = 65536;
        m_test_sizes[1] = 262144;
        m_test_sizes[2] = 1048576;
        m_test_sizes[3] = 4194304;
        m_test_sizes[4] = 8388608;
        m_test_sizes[5] = 16777216;
    }

    void on_open(connection_ptr con) {
        std::stringstream o;
        o << "Test 9." << m_minor << "." << m_subtest;
        m_name = o.str();

        m_data.reserve(m_test_sizes[m_subtest-1]);

        int timeout = 10000; // 10 sec

        // extend timeout to 100 sec for the longer tests
        if ((m_minor == 1 && m_subtest >= 3) || (m_minor == 2 && m_subtest >= 5)) {
            timeout = 100000;
        }

        if (m_minor == 1) {
            fill_utf8(m_data,m_test_sizes[m_subtest-1],true);
            start(con,timeout);
            con->send(m_data,websocketpp::frame::opcode::TEXT);
        } else if (m_minor == 2) {
            fill_binary(m_data,m_test_sizes[m_subtest-1],true);
            start(con,timeout);
            con->send(m_data,websocketpp::frame::opcode::BINARY);
        } else {
            std::cout << " has unknown definition." << std::endl;
        }
    }

    void on_message(connection_ptr con,websocketpp::message::data_ptr msg) {
        m_timer->cancel();
        mark();

        // Check whether the echoed data matches exactly
        m_pass = ((msg->get_payload() == m_data) ? PASS : FAIL);
        this->end(con);
    }
private:
    int         m_minor;
    int         m_subtest;
    int         m_test_sizes[6];
    std::string m_data;
};

// test class for 9.7.* and 9.8.*
class test_9_7_X : public case_handler {
public:
    test_9_7_X(int minor, int subtest)
    : m_minor(minor),
    m_subtest(subtest),
    m_acks(0)
    {
        // needs more C++11 intializer lists =(
        m_test_sizes[0] = 0;
        m_test_sizes[1] = 16;
        m_test_sizes[2] = 64;
        m_test_sizes[3] = 256;
        m_test_sizes[4] = 1024;
        m_test_sizes[5] = 4096;

        m_test_timeouts[0] = 60000;
        m_test_timeouts[1] = 60000;
        m_test_timeouts[2] = 60000;
        m_test_timeouts[3] = 120000;
        m_test_timeouts[4] = 240000;
        m_test_timeouts[5] = 480000;

        m_iterations = 1000;
    }

    void on_open(connection_ptr con) {
        std::stringstream o;
        o << "Test 9." << m_minor << "." << m_subtest;
        m_name = o.str();

        // Get a message buffer from the connection
        m_msg = con->get_data_message();

        // reserve space in our local data buffer
        m_data.reserve(m_test_sizes[m_subtest-1]);

        // Reset message to appropriate opcode and fill local buffer with
        // appropriate types of random data.
        if (m_minor == 7) {
            fill_utf8(m_data,m_test_sizes[m_subtest-1],true);
            m_msg->reset(websocketpp::frame::opcode::TEXT);
        } else if (m_minor == 8) {
            fill_binary(m_data,m_test_sizes[m_subtest-1],true);
            m_msg->reset(websocketpp::frame::opcode::BINARY);
        } else {
            std::cout << " has unknown definition." << std::endl;
            return;
        }

        m_msg->set_payload(m_data);

        // start test timer with 60-480 second timeout based on test length
        start(con,m_test_timeouts[m_subtest-1]);

        con->send(m_msg);

        // send 1000 copies of prepared message
        /*for (int i = 0; i < m_iterations; i++) {
         con->send(msg);
         }*/
    }

    void on_message(connection_ptr con, message_ptr msg) {
        if (msg->get_payload() == m_data) {
            m_acks++;
            mark();
        } else {
            mark();
            m_timer->cancel();
            m_msg.reset();
            this->end(con);
        }

        if (m_acks == m_iterations) {
            m_pass = PASS;
            mark();
            m_timer->cancel();
            m_msg.reset();
            this->end(con);
        } else {
            con->send(m_msg);
        }
    }
private:
    int         m_minor;
    int         m_subtest;
    int         m_test_timeouts[6];
    size_t      m_test_sizes[6];
    int         m_iterations;
    std::string m_data;
    int         m_acks;
    message_ptr m_msg;

};

} // namespace wsperf

#endif // WSPERF_CASE__AUTOBAHN_HPP<commit_msg>adds welcome message to wsperf, lots of wsperf cleanup<commit_after><|endoftext|>


<commit_before>/*
 * ImageWrapper_to_GLTexture.cpp
 *
 * Copyright (C) 2021 by VISUS (Universitaet Stuttgart).
 * Alle Rechte vorbehalten.
 */

#include "ImageWrapper_to_GLTexture.hpp"
#include "ImageWrapper_Conversion_Helpers.hpp"

#include "glad/gl.h"

#include <tuple>

using namespace megamol::frontend_resources;

namespace gl_wrapper_impl {

void gl_init_texture(unsigned int& handle) {
    glCreateTextures(GL_TEXTURE_2D, 1, &handle);
}

std::tuple<int, int, int> getInternalformatFormatType(ImageWrapper::DataChannels channels) {
    const auto internalformat = channels == ImageWrapper::DataChannels::RGB8 ? GL_RGB8 : GL_RGBA8;
    const auto format = channels == ImageWrapper::DataChannels::RGB8 ? GL_RGB : GL_RGBA;
    const auto type = GL_UNSIGNED_BYTE;

    return {internalformat, format, type};
}

void gl_set_and_resize_texture(unsigned int& handle, ImageWrapper::ImageSize size, ImageWrapper::DataChannels channels,
    const void* data = nullptr) {
    if (!handle)
        gl_init_texture(handle);

    int old_handle = 0;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_handle);

    glBindTexture(GL_TEXTURE_2D, handle);

    glTextureParameteri(handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTextureParameteri(handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTextureParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTextureParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    const auto [internalformat, format, type] = getInternalformatFormatType(channels);

    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, size.width, size.height, 0, format, type, data);

    glBindTexture(GL_TEXTURE_2D, old_handle);
}

void gl_copy_texture(unsigned int from_handle, unsigned int to_handle, ImageWrapper::ImageSize size) {
    glCopyImageSubData(
        from_handle, GL_TEXTURE_2D, 0, 0, 0, 0, to_handle, GL_TEXTURE_2D, 0, 0, 0, 0, size.width, size.height, 1);
}

void gl_delete_texture(unsigned int& handle) {
    glDeleteTextures(1, &handle);
    handle = 0;
}

void gl_download_texture_to_vector(
    unsigned int handle, ImageWrapper::ImageSize size, ImageWrapper::DataChannels channels, std::vector<byte>& target) {
    target.resize(size.width * size.height * 4); // see below

    const auto [internalformat, format, type] = getInternalformatFormatType(channels);

    // returns RGBA8 and fills unused components with defaults
    // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetTextureSubImage.xhtml
    // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetTexImage.xhtml
    glGetTextureSubImage(handle, 0, 0, 0, 0, size.width, size.height, 1, format, type, target.size(), target.data());
    //glGetTextureImage(handle, 0, format, type, target.size(), target.data());
}

void gl_upload_texture_from_vector(unsigned int& handle, ImageWrapper::ImageSize size,
    ImageWrapper::DataChannels channels, std::vector<byte> const& source) {
    gl_set_and_resize_texture(handle, size, channels, source.data());
}
} // namespace gl_wrapper_impl

gl_texture::~gl_texture() {
    if (this->texture != 0) {
        gl_wrapper_impl::gl_delete_texture(this->texture);
    }
    this->clear();
}

void gl_texture::from_image(ImageWrapper const& image) {
    this->image_wrapper_ptr = const_cast<ImageWrapper*>(&image);
    this->size = image.size;

    switch (image.type) {
    case WrappedImageType::ByteArray:
        gl_wrapper_impl::gl_set_and_resize_texture(
            this->texture, image.size, image.channels, conversion::to_vector(image.referenced_image_handle)->data());
        this->texture_reference = this->texture;
        break;
    case WrappedImageType::GLTexureHandle:
        this->texture_reference = conversion::to_uint(image.referenced_image_handle);
        break;
    }
}

void gl_texture::assign(gl_texture const& other, bool take_ownership) {
    this->image_wrapper_ptr = other.image_wrapper_ptr;
    this->size = other.size;

    if (take_ownership) {
        this->texture = other.texture;
    } else {
        if (other.texture != 0) {
            auto& image = *this->image_wrapper_ptr;
            gl_wrapper_impl::gl_set_and_resize_texture(this->texture, image.size, image.channels);
            gl_wrapper_impl::gl_copy_texture(other.texture, this->texture, image.size);
        }
    }

    if (other.texture_reference == other.texture) {
        this->texture_reference = this->texture;
    } else {
        this->texture_reference = other.texture_reference;
    }
}
<commit_msg>Update frontend/services/image_presentation/gl/ImageWrapper_to_GLTexture.cpp<commit_after>/*
 * ImageWrapper_to_GLTexture.cpp
 *
 * Copyright (C) 2021 by VISUS (Universitaet Stuttgart).
 * Alle Rechte vorbehalten.
 */

#include "ImageWrapper_to_GLTexture.hpp"
#include "ImageWrapper_Conversion_Helpers.hpp"

#include "glad/gl.h"

#include <tuple>

using namespace megamol::frontend_resources;

namespace gl_wrapper_impl {

void gl_init_texture(unsigned int& handle) {
    glCreateTextures(GL_TEXTURE_2D, 1, &handle);
}

std::tuple<int, int, int> getInternalformatFormatType(ImageWrapper::DataChannels channels) {
    if (channels != ImageWrapper::DataChannels::RGBA8 &&
        channels != ImageWrapper::DataChannels::RGB8) {
        throw std::runtime_error("[ImageWrapper_to_GLTexture.cpp] Only image with RGBA8 or RGA8 channels supported for now...");
    }

    const auto internalformat = channels == ImageWrapper::DataChannels::RGB8 ? GL_RGB8 : GL_RGBA8;
    const auto format = channels == ImageWrapper::DataChannels::RGB8 ? GL_RGB : GL_RGBA;
    const auto type = GL_UNSIGNED_BYTE;

    return {internalformat, format, type};
}

void gl_set_and_resize_texture(unsigned int& handle, ImageWrapper::ImageSize size, ImageWrapper::DataChannels channels,
    const void* data = nullptr) {
    if (!handle)
        gl_init_texture(handle);

    int old_handle = 0;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_handle);

    glBindTexture(GL_TEXTURE_2D, handle);

    glTextureParameteri(handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTextureParameteri(handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTextureParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTextureParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    const auto [internalformat, format, type] = getInternalformatFormatType(channels);

    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, size.width, size.height, 0, format, type, data);

    glBindTexture(GL_TEXTURE_2D, old_handle);
}

void gl_copy_texture(unsigned int from_handle, unsigned int to_handle, ImageWrapper::ImageSize size) {
    glCopyImageSubData(
        from_handle, GL_TEXTURE_2D, 0, 0, 0, 0, to_handle, GL_TEXTURE_2D, 0, 0, 0, 0, size.width, size.height, 1);
}

void gl_delete_texture(unsigned int& handle) {
    glDeleteTextures(1, &handle);
    handle = 0;
}

void gl_download_texture_to_vector(
    unsigned int handle, ImageWrapper::ImageSize size, ImageWrapper::DataChannels channels, std::vector<byte>& target) {
    target.resize(size.width * size.height * 4); // see below

    const auto [internalformat, format, type] = getInternalformatFormatType(channels);

    // returns RGBA8 and fills unused components with defaults
    // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetTextureSubImage.xhtml
    // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetTexImage.xhtml
    glGetTextureSubImage(handle, 0, 0, 0, 0, size.width, size.height, 1, format, type, target.size(), target.data());
    //glGetTextureImage(handle, 0, format, type, target.size(), target.data());
}

void gl_upload_texture_from_vector(unsigned int& handle, ImageWrapper::ImageSize size,
    ImageWrapper::DataChannels channels, std::vector<byte> const& source) {
    gl_set_and_resize_texture(handle, size, channels, source.data());
}
} // namespace gl_wrapper_impl

gl_texture::~gl_texture() {
    if (this->texture != 0) {
        gl_wrapper_impl::gl_delete_texture(this->texture);
    }
    this->clear();
}

void gl_texture::from_image(ImageWrapper const& image) {
    this->image_wrapper_ptr = const_cast<ImageWrapper*>(&image);
    this->size = image.size;

    switch (image.type) {
    case WrappedImageType::ByteArray:
        gl_wrapper_impl::gl_set_and_resize_texture(
            this->texture, image.size, image.channels, conversion::to_vector(image.referenced_image_handle)->data());
        this->texture_reference = this->texture;
        break;
    case WrappedImageType::GLTexureHandle:
        this->texture_reference = conversion::to_uint(image.referenced_image_handle);
        break;
    }
}

void gl_texture::assign(gl_texture const& other, bool take_ownership) {
    this->image_wrapper_ptr = other.image_wrapper_ptr;
    this->size = other.size;

    if (take_ownership) {
        this->texture = other.texture;
    } else {
        if (other.texture != 0) {
            auto& image = *this->image_wrapper_ptr;
            gl_wrapper_impl::gl_set_and_resize_texture(this->texture, image.size, image.channels);
            gl_wrapper_impl::gl_copy_texture(other.texture, this->texture, image.size);
        }
    }

    if (other.texture_reference == other.texture) {
        this->texture_reference = this->texture;
    } else {
        this->texture_reference = other.texture_reference;
    }
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h"

#include <cstdint>
#include <cstring>
#include <utility>

#include "absl/memory/memory.h"
#include "absl/types/optional.h"
#include "modules/video_coding/include/video_error_codes.h"
#include "rtc_base/logging.h"

namespace webrtc {
namespace test {

QualityAnalyzingVideoDecoder::QualityAnalyzingVideoDecoder(
    int id,
    std::unique_ptr<VideoDecoder> delegate,
    EncodedImageIdExtractor* extractor,
    VideoQualityAnalyzerInterface* analyzer)
    : id_(id),
      implementation_name_("AnalyzingDecoder-" +
                           std::string(delegate_->ImplementationName())),
      delegate_(std::move(delegate)),
      extractor_(extractor),
      analyzer_(analyzer) {
  analyzing_callback_ = absl::make_unique<DecoderCallback>(this);
}
QualityAnalyzingVideoDecoder::~QualityAnalyzingVideoDecoder() = default;

int32_t QualityAnalyzingVideoDecoder::InitDecode(
    const VideoCodec* codec_settings,
    int32_t number_of_cores) {
  return delegate_->InitDecode(codec_settings, number_of_cores);
}

int32_t QualityAnalyzingVideoDecoder::Decode(
    const EncodedImage& input_image,
    bool missing_frames,
    const CodecSpecificInfo* codec_specific_info,
    int64_t render_time_ms) {
  // Image  extractor extracts id from provided EncodedImage and also returns
  // the image with the original buffer. Buffer can be modified in place, so
  // owner of original buffer will be responsible for deleting it, or extractor
  // can create a new buffer. In such case extractor will be responsible for
  // deleting it.
  EncodedImageWithId out = extractor_->ExtractId(input_image, id_);

  EncodedImage* origin_image;
  {
    rtc::CritScope crit(&lock_);
    // Store id to be able to retrieve it in analyzing callback.
    timestamp_to_frame_id_.insert({input_image.Timestamp(), out.id});
    // Store encoded image to prevent its destruction while it is used in
    // decoder.
    origin_image = &(
        decoding_images_.insert({out.id, std::move(out.image)}).first->second);
  }
  // We can safely dereference |origin_image|, because it can be removed from
  // the map only after |delegate_| Decode method will be invoked. Image will be
  // removed inside DecodedImageCallback, which can be done on separate thread.
  analyzer_->OnFrameReceived(out.id, *origin_image);
  int32_t result = delegate_->Decode(*origin_image, missing_frames,
                                     codec_specific_info, render_time_ms);
  if (result != WEBRTC_VIDEO_CODEC_OK) {
    // If delegate decoder failed, then cleanup data for this image.
    {
      rtc::CritScope crit(&lock_);
      timestamp_to_frame_id_.erase(input_image.Timestamp());
      decoding_images_.erase(out.id);
    }
    analyzer_->OnDecoderError(out.id, result);
  }
  return result;
}

int32_t QualityAnalyzingVideoDecoder::RegisterDecodeCompleteCallback(
    DecodedImageCallback* callback) {
  analyzing_callback_->SetDelegateCallback(callback);
  return delegate_->RegisterDecodeCompleteCallback(analyzing_callback_.get());
}

int32_t QualityAnalyzingVideoDecoder::Release() {
  rtc::CritScope crit(&lock_);
  analyzing_callback_->SetDelegateCallback(nullptr);
  timestamp_to_frame_id_.clear();
  decoding_images_.clear();
  return delegate_->Release();
}

bool QualityAnalyzingVideoDecoder::PrefersLateDecoding() const {
  return delegate_->PrefersLateDecoding();
}

const char* QualityAnalyzingVideoDecoder::ImplementationName() const {
  return implementation_name_.c_str();
}

QualityAnalyzingVideoDecoder::DecoderCallback::DecoderCallback(
    QualityAnalyzingVideoDecoder* decoder)
    : decoder_(decoder), delegate_callback_(nullptr) {}
QualityAnalyzingVideoDecoder::DecoderCallback::~DecoderCallback() = default;

void QualityAnalyzingVideoDecoder::DecoderCallback::SetDelegateCallback(
    DecodedImageCallback* delegate) {
  rtc::CritScope crit(&callback_lock_);
  delegate_callback_ = delegate;
}

// We have to implement all next 3 methods because we don't know which one
// exactly is implemented in |delegate_callback_|, so we need to call the same
// method on |delegate_callback_|, as was called on |this| callback.
int32_t QualityAnalyzingVideoDecoder::DecoderCallback::Decoded(
    VideoFrame& decodedImage) {
  decoder_->OnFrameDecoded(&decodedImage, /*decode_time_ms=*/absl::nullopt,
                           /*qp=*/absl::nullopt);

  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->Decoded(decodedImage);
}

int32_t QualityAnalyzingVideoDecoder::DecoderCallback::Decoded(
    VideoFrame& decodedImage,
    int64_t decode_time_ms) {
  decoder_->OnFrameDecoded(&decodedImage, decode_time_ms, /*qp=*/absl::nullopt);

  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->Decoded(decodedImage, decode_time_ms);
}

void QualityAnalyzingVideoDecoder::DecoderCallback::Decoded(
    VideoFrame& decodedImage,
    absl::optional<int32_t> decode_time_ms,
    absl::optional<uint8_t> qp) {
  decoder_->OnFrameDecoded(&decodedImage, decode_time_ms, qp);

  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  delegate_callback_->Decoded(decodedImage, decode_time_ms, qp);
}

int32_t
QualityAnalyzingVideoDecoder::DecoderCallback::ReceivedDecodedReferenceFrame(
    const uint64_t pictureId) {
  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->ReceivedDecodedReferenceFrame(pictureId);
}

int32_t QualityAnalyzingVideoDecoder::DecoderCallback::ReceivedDecodedFrame(
    const uint64_t pictureId) {
  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->ReceivedDecodedFrame(pictureId);
}

void QualityAnalyzingVideoDecoder::OnFrameDecoded(
    VideoFrame* frame,
    absl::optional<int32_t> decode_time_ms,
    absl::optional<uint8_t> qp) {
  uint16_t frame_id;
  {
    rtc::CritScope crit(&lock_);
    auto it = timestamp_to_frame_id_.find(frame->timestamp());
    if (it == timestamp_to_frame_id_.end()) {
      // Ensure, that we have info about this frame. It can happen that for some
      // reasons decoder response, that he failed to decode, when we were
      // posting frame to it, but then call the callback for this frame.
      RTC_LOG(LS_ERROR) << "QualityAnalyzingVideoDecoder::OnFrameDecoded: No "
                           "frame id for frame for frame->timestamp()="
                        << frame->timestamp();
      return;
    }
    frame_id = it->second;
    timestamp_to_frame_id_.erase(it);
    decoding_images_.erase(frame_id);
  }
  // Set frame id to the value, that was extracted from corresponding encoded
  // image.
  frame->set_id(frame_id);
  analyzer_->OnFrameDecoded(*frame, decode_time_ms, qp);
}

QualityAnalyzingVideoDecoderFactory::QualityAnalyzingVideoDecoderFactory(
    std::unique_ptr<VideoDecoderFactory> delegate,
    IdGenerator<int>* id_generator,
    EncodedImageIdExtractor* extractor,
    VideoQualityAnalyzerInterface* analyzer)
    : delegate_(std::move(delegate)),
      id_generator_(id_generator),
      extractor_(extractor),
      analyzer_(analyzer) {}
QualityAnalyzingVideoDecoderFactory::~QualityAnalyzingVideoDecoderFactory() =
    default;

std::vector<SdpVideoFormat>
QualityAnalyzingVideoDecoderFactory::GetSupportedFormats() const {
  return delegate_->GetSupportedFormats();
}

std::unique_ptr<VideoDecoder>
QualityAnalyzingVideoDecoderFactory::CreateVideoDecoder(
    const SdpVideoFormat& format) {
  std::unique_ptr<VideoDecoder> decoder = delegate_->CreateVideoDecoder(format);
  return absl::make_unique<QualityAnalyzingVideoDecoder>(
      id_generator_->GetNextId(), std::move(decoder), extractor_, analyzer_);
}

std::unique_ptr<VideoDecoder>
QualityAnalyzingVideoDecoderFactory::LegacyCreateVideoDecoder(
    const SdpVideoFormat& format,
    const std::string& receive_stream_id) {
  std::unique_ptr<VideoDecoder> decoder =
      delegate_->LegacyCreateVideoDecoder(format, receive_stream_id);
  return absl::make_unique<QualityAnalyzingVideoDecoder>(
      id_generator_->GetNextId(), std::move(decoder), extractor_, analyzer_);
}

}  // namespace test
}  // namespace webrtc
<commit_msg>Fix initialization to prevent SIGSEGV<commit_after>/*
 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h"

#include <cstdint>
#include <cstring>
#include <utility>

#include "absl/memory/memory.h"
#include "absl/types/optional.h"
#include "modules/video_coding/include/video_error_codes.h"
#include "rtc_base/logging.h"

namespace webrtc {
namespace test {

QualityAnalyzingVideoDecoder::QualityAnalyzingVideoDecoder(
    int id,
    std::unique_ptr<VideoDecoder> delegate,
    EncodedImageIdExtractor* extractor,
    VideoQualityAnalyzerInterface* analyzer)
    : id_(id),
      implementation_name_("AnalyzingDecoder-" +
                           std::string(delegate->ImplementationName())),
      delegate_(std::move(delegate)),
      extractor_(extractor),
      analyzer_(analyzer) {
  analyzing_callback_ = absl::make_unique<DecoderCallback>(this);
}
QualityAnalyzingVideoDecoder::~QualityAnalyzingVideoDecoder() = default;

int32_t QualityAnalyzingVideoDecoder::InitDecode(
    const VideoCodec* codec_settings,
    int32_t number_of_cores) {
  return delegate_->InitDecode(codec_settings, number_of_cores);
}

int32_t QualityAnalyzingVideoDecoder::Decode(
    const EncodedImage& input_image,
    bool missing_frames,
    const CodecSpecificInfo* codec_specific_info,
    int64_t render_time_ms) {
  // Image  extractor extracts id from provided EncodedImage and also returns
  // the image with the original buffer. Buffer can be modified in place, so
  // owner of original buffer will be responsible for deleting it, or extractor
  // can create a new buffer. In such case extractor will be responsible for
  // deleting it.
  EncodedImageWithId out = extractor_->ExtractId(input_image, id_);

  EncodedImage* origin_image;
  {
    rtc::CritScope crit(&lock_);
    // Store id to be able to retrieve it in analyzing callback.
    timestamp_to_frame_id_.insert({input_image.Timestamp(), out.id});
    // Store encoded image to prevent its destruction while it is used in
    // decoder.
    origin_image = &(
        decoding_images_.insert({out.id, std::move(out.image)}).first->second);
  }
  // We can safely dereference |origin_image|, because it can be removed from
  // the map only after |delegate_| Decode method will be invoked. Image will be
  // removed inside DecodedImageCallback, which can be done on separate thread.
  analyzer_->OnFrameReceived(out.id, *origin_image);
  int32_t result = delegate_->Decode(*origin_image, missing_frames,
                                     codec_specific_info, render_time_ms);
  if (result != WEBRTC_VIDEO_CODEC_OK) {
    // If delegate decoder failed, then cleanup data for this image.
    {
      rtc::CritScope crit(&lock_);
      timestamp_to_frame_id_.erase(input_image.Timestamp());
      decoding_images_.erase(out.id);
    }
    analyzer_->OnDecoderError(out.id, result);
  }
  return result;
}

int32_t QualityAnalyzingVideoDecoder::RegisterDecodeCompleteCallback(
    DecodedImageCallback* callback) {
  analyzing_callback_->SetDelegateCallback(callback);
  return delegate_->RegisterDecodeCompleteCallback(analyzing_callback_.get());
}

int32_t QualityAnalyzingVideoDecoder::Release() {
  rtc::CritScope crit(&lock_);
  analyzing_callback_->SetDelegateCallback(nullptr);
  timestamp_to_frame_id_.clear();
  decoding_images_.clear();
  return delegate_->Release();
}

bool QualityAnalyzingVideoDecoder::PrefersLateDecoding() const {
  return delegate_->PrefersLateDecoding();
}

const char* QualityAnalyzingVideoDecoder::ImplementationName() const {
  return implementation_name_.c_str();
}

QualityAnalyzingVideoDecoder::DecoderCallback::DecoderCallback(
    QualityAnalyzingVideoDecoder* decoder)
    : decoder_(decoder), delegate_callback_(nullptr) {}
QualityAnalyzingVideoDecoder::DecoderCallback::~DecoderCallback() = default;

void QualityAnalyzingVideoDecoder::DecoderCallback::SetDelegateCallback(
    DecodedImageCallback* delegate) {
  rtc::CritScope crit(&callback_lock_);
  delegate_callback_ = delegate;
}

// We have to implement all next 3 methods because we don't know which one
// exactly is implemented in |delegate_callback_|, so we need to call the same
// method on |delegate_callback_|, as was called on |this| callback.
int32_t QualityAnalyzingVideoDecoder::DecoderCallback::Decoded(
    VideoFrame& decodedImage) {
  decoder_->OnFrameDecoded(&decodedImage, /*decode_time_ms=*/absl::nullopt,
                           /*qp=*/absl::nullopt);

  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->Decoded(decodedImage);
}

int32_t QualityAnalyzingVideoDecoder::DecoderCallback::Decoded(
    VideoFrame& decodedImage,
    int64_t decode_time_ms) {
  decoder_->OnFrameDecoded(&decodedImage, decode_time_ms, /*qp=*/absl::nullopt);

  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->Decoded(decodedImage, decode_time_ms);
}

void QualityAnalyzingVideoDecoder::DecoderCallback::Decoded(
    VideoFrame& decodedImage,
    absl::optional<int32_t> decode_time_ms,
    absl::optional<uint8_t> qp) {
  decoder_->OnFrameDecoded(&decodedImage, decode_time_ms, qp);

  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  delegate_callback_->Decoded(decodedImage, decode_time_ms, qp);
}

int32_t
QualityAnalyzingVideoDecoder::DecoderCallback::ReceivedDecodedReferenceFrame(
    const uint64_t pictureId) {
  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->ReceivedDecodedReferenceFrame(pictureId);
}

int32_t QualityAnalyzingVideoDecoder::DecoderCallback::ReceivedDecodedFrame(
    const uint64_t pictureId) {
  rtc::CritScope crit(&callback_lock_);
  RTC_DCHECK(delegate_callback_);
  return delegate_callback_->ReceivedDecodedFrame(pictureId);
}

void QualityAnalyzingVideoDecoder::OnFrameDecoded(
    VideoFrame* frame,
    absl::optional<int32_t> decode_time_ms,
    absl::optional<uint8_t> qp) {
  uint16_t frame_id;
  {
    rtc::CritScope crit(&lock_);
    auto it = timestamp_to_frame_id_.find(frame->timestamp());
    if (it == timestamp_to_frame_id_.end()) {
      // Ensure, that we have info about this frame. It can happen that for some
      // reasons decoder response, that he failed to decode, when we were
      // posting frame to it, but then call the callback for this frame.
      RTC_LOG(LS_ERROR) << "QualityAnalyzingVideoDecoder::OnFrameDecoded: No "
                           "frame id for frame for frame->timestamp()="
                        << frame->timestamp();
      return;
    }
    frame_id = it->second;
    timestamp_to_frame_id_.erase(it);
    decoding_images_.erase(frame_id);
  }
  // Set frame id to the value, that was extracted from corresponding encoded
  // image.
  frame->set_id(frame_id);
  analyzer_->OnFrameDecoded(*frame, decode_time_ms, qp);
}

QualityAnalyzingVideoDecoderFactory::QualityAnalyzingVideoDecoderFactory(
    std::unique_ptr<VideoDecoderFactory> delegate,
    IdGenerator<int>* id_generator,
    EncodedImageIdExtractor* extractor,
    VideoQualityAnalyzerInterface* analyzer)
    : delegate_(std::move(delegate)),
      id_generator_(id_generator),
      extractor_(extractor),
      analyzer_(analyzer) {}
QualityAnalyzingVideoDecoderFactory::~QualityAnalyzingVideoDecoderFactory() =
    default;

std::vector<SdpVideoFormat>
QualityAnalyzingVideoDecoderFactory::GetSupportedFormats() const {
  return delegate_->GetSupportedFormats();
}

std::unique_ptr<VideoDecoder>
QualityAnalyzingVideoDecoderFactory::CreateVideoDecoder(
    const SdpVideoFormat& format) {
  std::unique_ptr<VideoDecoder> decoder = delegate_->CreateVideoDecoder(format);
  return absl::make_unique<QualityAnalyzingVideoDecoder>(
      id_generator_->GetNextId(), std::move(decoder), extractor_, analyzer_);
}

std::unique_ptr<VideoDecoder>
QualityAnalyzingVideoDecoderFactory::LegacyCreateVideoDecoder(
    const SdpVideoFormat& format,
    const std::string& receive_stream_id) {
  std::unique_ptr<VideoDecoder> decoder =
      delegate_->LegacyCreateVideoDecoder(format, receive_stream_id);
  return absl::make_unique<QualityAnalyzingVideoDecoder>(
      id_generator_->GetNextId(), std::move(decoder), extractor_, analyzer_);
}

}  // namespace test
}  // namespace webrtc
<|endoftext|>