<commit_before>#ifndef __STAN__PROB__DISTRIBUTIONS__PARETO_HPP__
#define __STAN__PROB__DISTRIBUTIONS__PARETO_HPP__

#include <stan/agrad.hpp>
#include <stan/math/error_handling.hpp>
#include <stan/math/special_functions.hpp>
#include <stan/meta/traits.hpp>
#include <stan/prob/constants.hpp>
#include <stan/prob/traits.hpp>

namespace stan {
  namespace prob {

    // Pareto(y|y_m,alpha)  [y > y_m;  y_m > 0;  alpha > 0]
    template <bool propto,
              typename T_y, typename T_scale, typename T_shape,
              class Policy>
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha,
               const Policy&) {
      static const char* function = "stan::prob::pareto_log(%1%)";

      using stan::math::value_of;
      using stan::math::check_finite;
      using stan::math::check_positive;
      using stan::math::check_not_nan;
      using stan::math::check_consistent_sizes;

      // check if any vectors are zero length
      if (!(stan::length(y)
            && stan::length(y_min)
            && stan::length(alpha)))
        return 0.0;

      // set up return value accumulator
      double logp(0.0);

      // validate args (here done over var, which should be OK)
      if (!check_not_nan(function, y, "Random variable", &logp, Policy()))
        return logp;
      if (!check_finite(function, y_min, "Scale parameter",
                        &logp, Policy()))
        return logp;
      if (!check_positive(function, y_min, "Scale parameter",
                          &logp, Policy()))
        return logp;
      if (!check_finite(function, alpha, "Shape parameter",
                        &logp, Policy()))
        return logp;
      if (!check_positive(function, alpha, "Shape parameter",
                          &logp, Policy()))
        return logp;
      if (!(check_consistent_sizes(function,
				   y,y_min,alpha,
				   "Random variable","Scale parameter","Shape parameter",
                                   &logp, Policy())))
        return logp;

      // check if no variables are involved and prop-to
      if (!include_summand<propto,T_y,T_scale,T_shape>::value)
	return 0.0;

      VectorView<const T_y> y_vec(y);
      VectorView<const T_scale> y_min_vec(y_min);
      VectorView<const T_shape> alpha_vec(alpha);
      size_t N = max_size(y, y_min, alpha);

      for (size_t n = 0; n < N; n++) {
	if (y_vec[n] < y_min_vec[n])
	  return LOG_ZERO;
      }

      // set up template expressions wrapping scalars into vector views
      agrad::OperandsAndPartials<T_y,T_scale,T_shape> operands_and_partials(y, y_min, alpha);

      DoubleVectorView<include_summand<propto,T_y,T_shape>::value,T_y> log_y(length(y));
      if (include_summand<propto,T_y,T_shape>::value)
	for (size_t n = 0; n < length(y); n++)
	  log_y[n] = log(value_of(y_vec[n]));
      DoubleVectorView<!is_constant_struct<T_y>::value||!is_constant_struct<T_shape>::value,T_y> inv_y(length(y));
      if (!is_constant_struct<T_y>::value||!is_constant_struct<T_shape>::value)
	for (size_t n = 0; n < length(y); n++)
	  inv_y[n] = 1 / value_of(y_vec[n]);
      DoubleVectorView<include_summand<propto,T_scale,T_shape>::value,T_scale>
	log_y_min(length(y_min));
      if (include_summand<propto,T_scale,T_shape>::value)
	for (size_t n = 0; n < length(y_min); n++)
	  log_y_min[n] = log(value_of(y_min_vec[n]));
      DoubleVectorView<include_summand<propto,T_shape>::value,T_shape> log_alpha(length(alpha));
      if (include_summand<propto,T_shape>::value)
	for (size_t n = 0; n < length(alpha); n++)
	  log_alpha[n] = log(value_of(alpha_vec[n]));

      DoubleVectorView<!is_constant_struct<T_shape>::value,T_shape> inv_alpha(length(alpha));
      if (!is_constant_struct<T_shape>::value)
	for (size_t n = 0; n < length(alpha); n++)
	  inv_alpha[n] = 1 / value_of(alpha_vec[n]);

      using stan::math::multiply_log;

      for (size_t n = 0; n < N; n++) {
	const double alpha_dbl = value_of(alpha_vec[n]);
	// log probability
	if (include_summand<propto,T_shape>::value)
	  logp += log_alpha[n];
	if (include_summand<propto,T_scale,T_shape>::value)
	  logp += alpha_dbl * log_y_min[n];
	if (include_summand<propto,T_y,T_shape>::value)
	  logp -= alpha_dbl * log_y[n] + log_y[n];

	// gradients
	if (!is_constant_struct<T_y>::value)
	  operands_and_partials.d_x1[n] -= alpha_dbl * inv_y[n] + inv_y[n];
	if (!is_constant_struct<T_scale>::value)
	  operands_and_partials.d_x2[n] += alpha_dbl / value_of(y_min_vec[n]);
	if (!is_constant_struct<T_shape>::value)
	  operands_and_partials.d_x3[n] += 1 / alpha_dbl + log_y_min[n] - log_y[n];
      }
      return operands_and_partials.to_var(logp);
    }

    template <bool propto,
              typename T_y, typename T_scale, typename T_shape>
    inline
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha) {
      return pareto_log<propto>(y,y_min,alpha,stan::math::default_policy());
    }

    template <typename T_y, typename T_scale, typename T_shape,
              class Policy>
    inline
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha,
               const Policy&) {
      return pareto_log<false>(y,y_min,alpha,Policy());
    }

    template <typename T_y, typename T_scale, typename T_shape>
    inline
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha) {
      return pareto_log<false>(y,y_min,alpha,stan::math::default_policy());
    }

      template <typename T_y, typename T_scale, typename T_shape, class Policy>
      typename return_type<T_y, T_scale, T_shape>::type
      pareto_cdf(const T_y& y, const T_scale& y_min, const T_shape& alpha, const Policy&) {

          // Check sizes
          // Size checks
          if ( !( stan::length(y) && stan::length(y_min) && stan::length(alpha) ) ) return 0.0;

          // Check errors
          static const char* function = "stan::prob::pareto_cdf(%1%)";

          using stan::math::check_finite;
          using stan::math::check_positive;
          using stan::math::check_not_nan;
          using stan::math::check_greater_or_equal;
          using stan::math::check_consistent_sizes;

          using boost::math::tools::promote_args;

          double P(1.0);

          if (!check_not_nan(function, y, "Random variable", &P, Policy()))
              return P;

          if (!check_greater_or_equal(function, y, y_min, "Random variable", &P, Policy()))
              return P;

          if (!check_finite(function, y_min, "Scale parameter", &P, Policy()))
              return P;

          if (!check_positive(function, y_min, "Scale parameter", &P, Policy()))
              return P;

          if (!check_finite(function, alpha, "Shape parameter", &P, Policy()))
              return P;

          if (!check_positive(function, alpha, "Shape parameter", &P, Policy()))
              return P;

          if (!(check_consistent_sizes(function, y, y_min, alpha,
                                       "Random variable", "Scale parameter", "Shape parameter",
                                       &P, Policy())))
              return P;

          // Wrap arguments in vectors
          VectorView<const T_y> y_vec(y);
          VectorView<const T_scale> y_min_vec(y_min);
          VectorView<const T_shape> alpha_vec(alpha);
          size_t N = max_size(y, y_min, alpha);

          agrad::OperandsAndPartials<T_y, T_scale, T_shape> operands_and_partials(y, y_min, alpha);

          std::fill(operands_and_partials.all_partials,
                    operands_and_partials.all_partials + operands_and_partials.nvaris, 0.0);

          // Compute vectorized CDF and its gradients
          using stan::math::value_of;

          for (size_t n = 0; n < N; n++) {

              // Pull out values
              const double log_dbl = log( value_of(y_min_vec[n]) / value_of(y_vec[n]) );
              const double y_min_inv_dbl = 1.0 / value_of(y_min_vec[n]);
              const double alpha_dbl = value_of(alpha_vec[n]);

              // Compute
              const double Pn = 1.0 - exp( alpha_dbl * log_dbl );

              P *= Pn;

              if (!is_constant_struct<T_y>::value)
                  operands_and_partials.d_x1[n]
                  += alpha_dbl * y_min_inv_dbl * exp( (alpha_dbl + 1) * log_dbl ) / Pn;

              if (!is_constant_struct<T_scale>::value)
                  operands_and_partials.d_x2[n]
                  += - alpha_dbl * y_min_inv_dbl * exp( alpha_dbl * log_dbl ) / Pn;

              if (!is_constant_struct<T_shape>::value)
                  operands_and_partials.d_x3[n]
                  += - exp( alpha_dbl * log_dbl ) * log_dbl / Pn;

          }

          for (size_t n = 0; n < N; n++) {

              if (!is_constant_struct<T_y>::value)
                  operands_and_partials.d_x1[n] *= P;

              if (!is_constant_struct<T_scale>::value)
                  operands_and_partials.d_x2[n] *= P;

              if (!is_constant_struct<T_shape>::value)
                  operands_and_partials.d_x3[n] *= P;

          }

          return operands_and_partials.to_var(P);

      }

      template <typename T_y, typename T_scale, typename T_shape>
      inline typename return_type<T_y, T_scale, T_shape>::type
      pareto_cdf(const T_y& y, const T_scale& y_min, const T_shape& alpha) {
          return pareto_cdf(y, y_min, alpha, stan::math::default_policy());
      }

  }
}
#endif
<commit_msg>refactoring pareto distribution<commit_after>#ifndef __STAN__PROB__DISTRIBUTIONS__PARETO_HPP__
#define __STAN__PROB__DISTRIBUTIONS__PARETO_HPP__

#include <stan/agrad.hpp>
#include <stan/math/error_handling.hpp>
#include <stan/math/special_functions.hpp>
#include <stan/meta/traits.hpp>
#include <stan/prob/constants.hpp>
#include <stan/prob/traits.hpp>

namespace stan {
  namespace prob {

    // Pareto(y|y_m,alpha)  [y > y_m;  y_m > 0;  alpha > 0]
    template <bool propto,
              typename T_y, typename T_scale, typename T_shape,
              class Policy>
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha,
               const Policy&) {
      static const char* function = "stan::prob::pareto_log(%1%)";

      using stan::math::value_of;
      using stan::math::check_finite;
      using stan::math::check_positive;
      using stan::math::check_not_nan;
      using stan::math::check_consistent_sizes;

      // check if any vectors are zero length
      if (!(stan::length(y)
            && stan::length(y_min)
            && stan::length(alpha)))
        return 0.0;

      // set up return value accumulator
      double logp(0.0);

      // validate args (here done over var, which should be OK)
      if (!check_not_nan(function, y, "Random variable", &logp, Policy()))
        return logp;
      if (!check_finite(function, y_min, "Scale parameter",
                        &logp, Policy()))
        return logp;
      if (!check_positive(function, y_min, "Scale parameter",
                          &logp, Policy()))
        return logp;
      if (!check_finite(function, alpha, "Shape parameter",
                        &logp, Policy()))
        return logp;
      if (!check_positive(function, alpha, "Shape parameter",
                          &logp, Policy()))
        return logp;
      if (!(check_consistent_sizes(function,
				   y,y_min,alpha,
				   "Random variable","Scale parameter","Shape parameter",
                                   &logp, Policy())))
        return logp;

      // check if no variables are involved and prop-to
      if (!include_summand<propto,T_y,T_scale,T_shape>::value)
	return 0.0;

      VectorView<const T_y> y_vec(y);
      VectorView<const T_scale> y_min_vec(y_min);
      VectorView<const T_shape> alpha_vec(alpha);
      size_t N = max_size(y, y_min, alpha);

      for (size_t n = 0; n < N; n++) {
	if (y_vec[n] < y_min_vec[n])
	  return LOG_ZERO;
      }

      // set up template expressions wrapping scalars into vector views
      agrad::OperandsAndPartials<T_y,T_scale,T_shape> operands_and_partials(y, y_min, alpha);

      DoubleVectorView<include_summand<propto,T_y,T_shape>::value,is_vector<T_y>::value> log_y(length(y));
      if (include_summand<propto,T_y,T_shape>::value)
	for (size_t n = 0; n < length(y); n++)
	  log_y[n] = log(value_of(y_vec[n]));
      DoubleVectorView<!is_constant_struct<T_y>::value||!is_constant_struct<T_shape>::value,is_vector<T_y>::value> inv_y(length(y));
      if (!is_constant_struct<T_y>::value||!is_constant_struct<T_shape>::value)
	for (size_t n = 0; n < length(y); n++)
	  inv_y[n] = 1 / value_of(y_vec[n]);
      DoubleVectorView<include_summand<propto,T_scale,T_shape>::value,is_vector<T_scale>::value>
	log_y_min(length(y_min));
      if (include_summand<propto,T_scale,T_shape>::value)
	for (size_t n = 0; n < length(y_min); n++)
	  log_y_min[n] = log(value_of(y_min_vec[n]));
      DoubleVectorView<include_summand<propto,T_shape>::value,is_vector<T_shape>::value> log_alpha(length(alpha));
      if (include_summand<propto,T_shape>::value)
	for (size_t n = 0; n < length(alpha); n++)
	  log_alpha[n] = log(value_of(alpha_vec[n]));

      DoubleVectorView<!is_constant_struct<T_shape>::value,is_vector<T_shape>::value> inv_alpha(length(alpha));
      if (!is_constant_struct<T_shape>::value)
	for (size_t n = 0; n < length(alpha); n++)
	  inv_alpha[n] = 1 / value_of(alpha_vec[n]);

      using stan::math::multiply_log;

      for (size_t n = 0; n < N; n++) {
	const double alpha_dbl = value_of(alpha_vec[n]);
	// log probability
	if (include_summand<propto,T_shape>::value)
	  logp += log_alpha[n];
	if (include_summand<propto,T_scale,T_shape>::value)
	  logp += alpha_dbl * log_y_min[n];
	if (include_summand<propto,T_y,T_shape>::value)
	  logp -= alpha_dbl * log_y[n] + log_y[n];

	// gradients
	if (!is_constant_struct<T_y>::value)
	  operands_and_partials.d_x1[n] -= alpha_dbl * inv_y[n] + inv_y[n];
	if (!is_constant_struct<T_scale>::value)
	  operands_and_partials.d_x2[n] += alpha_dbl / value_of(y_min_vec[n]);
	if (!is_constant_struct<T_shape>::value)
	  operands_and_partials.d_x3[n] += 1 / alpha_dbl + log_y_min[n] - log_y[n];
      }
      return operands_and_partials.to_var(logp);
    }

    template <bool propto,
              typename T_y, typename T_scale, typename T_shape>
    inline
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha) {
      return pareto_log<propto>(y,y_min,alpha,stan::math::default_policy());
    }

    template <typename T_y, typename T_scale, typename T_shape,
              class Policy>
    inline
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha,
               const Policy&) {
      return pareto_log<false>(y,y_min,alpha,Policy());
    }

    template <typename T_y, typename T_scale, typename T_shape>
    inline
    typename return_type<T_y,T_scale,T_shape>::type
    pareto_log(const T_y& y, const T_scale& y_min, const T_shape& alpha) {
      return pareto_log<false>(y,y_min,alpha,stan::math::default_policy());
    }

      template <typename T_y, typename T_scale, typename T_shape, class Policy>
      typename return_type<T_y, T_scale, T_shape>::type
      pareto_cdf(const T_y& y, const T_scale& y_min, const T_shape& alpha, const Policy&) {

          // Check sizes
          // Size checks
          if ( !( stan::length(y) && stan::length(y_min) && stan::length(alpha) ) ) return 0.0;

          // Check errors
          static const char* function = "stan::prob::pareto_cdf(%1%)";

          using stan::math::check_finite;
          using stan::math::check_positive;
          using stan::math::check_not_nan;
          using stan::math::check_greater_or_equal;
          using stan::math::check_consistent_sizes;

          using boost::math::tools::promote_args;

          double P(1.0);

          if (!check_not_nan(function, y, "Random variable", &P, Policy()))
              return P;

          if (!check_greater_or_equal(function, y, y_min, "Random variable", &P, Policy()))
              return P;

          if (!check_finite(function, y_min, "Scale parameter", &P, Policy()))
              return P;

          if (!check_positive(function, y_min, "Scale parameter", &P, Policy()))
              return P;

          if (!check_finite(function, alpha, "Shape parameter", &P, Policy()))
              return P;

          if (!check_positive(function, alpha, "Shape parameter", &P, Policy()))
              return P;

          if (!(check_consistent_sizes(function, y, y_min, alpha,
                                       "Random variable", "Scale parameter", "Shape parameter",
                                       &P, Policy())))
              return P;

          // Wrap arguments in vectors
          VectorView<const T_y> y_vec(y);
          VectorView<const T_scale> y_min_vec(y_min);
          VectorView<const T_shape> alpha_vec(alpha);
          size_t N = max_size(y, y_min, alpha);

          agrad::OperandsAndPartials<T_y, T_scale, T_shape> operands_and_partials(y, y_min, alpha);

          std::fill(operands_and_partials.all_partials,
                    operands_and_partials.all_partials + operands_and_partials.nvaris, 0.0);

          // Compute vectorized CDF and its gradients
          using stan::math::value_of;

          for (size_t n = 0; n < N; n++) {

              // Pull out values
              const double log_dbl = log( value_of(y_min_vec[n]) / value_of(y_vec[n]) );
              const double y_min_inv_dbl = 1.0 / value_of(y_min_vec[n]);
              const double alpha_dbl = value_of(alpha_vec[n]);

              // Compute
              const double Pn = 1.0 - exp( alpha_dbl * log_dbl );

              P *= Pn;

              if (!is_constant_struct<T_y>::value)
                  operands_and_partials.d_x1[n]
                  += alpha_dbl * y_min_inv_dbl * exp( (alpha_dbl + 1) * log_dbl ) / Pn;

              if (!is_constant_struct<T_scale>::value)
                  operands_and_partials.d_x2[n]
                  += - alpha_dbl * y_min_inv_dbl * exp( alpha_dbl * log_dbl ) / Pn;

              if (!is_constant_struct<T_shape>::value)
                  operands_and_partials.d_x3[n]
                  += - exp( alpha_dbl * log_dbl ) * log_dbl / Pn;

          }

          for (size_t n = 0; n < N; n++) {

              if (!is_constant_struct<T_y>::value)
                  operands_and_partials.d_x1[n] *= P;

              if (!is_constant_struct<T_scale>::value)
                  operands_and_partials.d_x2[n] *= P;

              if (!is_constant_struct<T_shape>::value)
                  operands_and_partials.d_x3[n] *= P;

          }

          return operands_and_partials.to_var(P);

      }

      template <typename T_y, typename T_scale, typename T_shape>
      inline typename return_type<T_y, T_scale, T_shape>::type
      pareto_cdf(const T_y& y, const T_scale& y_min, const T_shape& alpha) {
          return pareto_cdf(y, y_min, alpha, stan::math::default_policy());
      }

  }
}
#endif
<|endoftext|>


<commit_before>/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 SensorProxy.cpp
 Copyright (c) 2016 Automatic Orchestra

 See the COPYRIGHT file at the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/COPYRIGHT.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 This file is part of Automatic Orchestra. It is subject to the license terms
 in the LICENSE file found in the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/LICENSE.

 No part of Automatic Orchestra, including this file, may be copied, modified,
 propagated, or distributed except according to the terms contained in the
 LICENSE file.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/

#include "SensorProxy.h"
#include "SensorMessages.h"

SensorProxy::SensorProxy(uint8_t pPin) : mPin(pPin) {
}

SensorProxy::~SensorProxy() {
  delete[] mBuffer;
}

void SensorProxy::update() {
  // uint16_t pinValue = analogRead(mPin);
  // mNormalizer->push(pinValue);
  // if(mNormalizer->hasNew()) {
  //   //TODO write value into buffer
  //   if (mValueCallback != NULL) {
  //       (*mValueCallback)(mNormalizer->get());
  //   }
  // }
  if(mBuffering) {
    unsigned long t = micros();
    if(t - mLastBufferTime >= BUFFER_CAPTURE_TIME_OFFSET) {
      captureBufferValue();
      mLastBufferTime = t;
    }
  }
}

void SensorProxy::startBuffering() {
  Serial.println("(SP) -> startBuffering()");
  mLastBufferTime = micros();
  captureBufferValue();
  mBuffering = true;
}

void SensorProxy::setMessageCallback(void (*pCallback)(uint8_t, uint16_t)) {
  mCallback = pCallback;
}

void SensorProxy::sendMessage(uint8_t pMessage, uint16_t pValue) {
  if(mCallback) {
    (* mCallback)(pMessage, pValue);
  }
}

void SensorProxy::captureBufferValue() {
  if(mBufferIndex == BUFFER_SIZE) {
    Serial.println("(SP) -> captureBufferValue(): Buffer is full.");
    sendMessage(SensorMessages::BUFFER_FULL);
    mBuffering = false;
  } else {
    uint16_t pinValue = analogRead(mPin);
    mBuffer[mBufferIndex] = pinValue;
    mapSensorToNote();
    Serial.print("(SP) -> captureBufferValue(): wrote value to buffer: ");
    Serial.println(mBuffer[mBufferIndex]);
    Serial.print("(SP) -> mapSensorToNote(): mapped value to note: ");
    Serial.println(mNotes[mBufferIndex]);
    mBufferIndex++;
  }
}

void SensorProxy::mapSensorToNote() {
  mNotes[mBufferIndex] = map(mBuffer[mBufferIndex],0,1023,36,95);
}

<commit_msg>SensorProxy debug condition implementation<commit_after>/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 SensorProxy.cpp
 Copyright (c) 2016 Automatic Orchestra

 See the COPYRIGHT file at the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/COPYRIGHT.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 This file is part of Automatic Orchestra. It is subject to the license terms
 in the LICENSE file found in the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/LICENSE.

 No part of Automatic Orchestra, including this file, may be copied, modified,
 propagated, or distributed except according to the terms contained in the
 LICENSE file.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/

#include "SensorProxy.h"
#include "SensorMessages.h"

#define PS_DEBUG true

SensorProxy::SensorProxy(uint8_t pPin) : mPin(pPin) {
}

SensorProxy::~SensorProxy() {
  delete[] mBuffer;
}

void SensorProxy::update() {
  // uint16_t pinValue = analogRead(mPin);
  // mNormalizer->push(pinValue);
  // if(mNormalizer->hasNew()) {
  //   //TODO write value into buffer
  //   if (mValueCallback != NULL) {
  //       (*mValueCallback)(mNormalizer->get());
  //   }
  // }
  if(mBuffering) {
    unsigned long t = micros();
    if(t - mLastBufferTime >= BUFFER_CAPTURE_TIME_OFFSET) {
      captureBufferValue();
      mLastBufferTime = t;
    }
  }
}

void SensorProxy::startBuffering() {
  #if PS_DEBUG
    Serial.println("(SP) -> startBuffering()");
  #endif
  mLastBufferTime = micros();
  captureBufferValue();
  mBuffering = true;
}

void SensorProxy::setMessageCallback(void (*pCallback)(uint8_t, uint16_t)) {
  mCallback = pCallback;
}

void SensorProxy::sendMessage(uint8_t pMessage, uint16_t pValue) {
  if(mCallback) {
    (* mCallback)(pMessage, pValue);
  }
}

void SensorProxy::captureBufferValue() {
  if(mBufferIndex == BUFFER_SIZE) {
    #if PS_DEBUG
      Serial.println("(SP) -> captureBufferValue(): Buffer is full.");
    #endif
    sendMessage(SensorMessages::BUFFER_FULL);
    mBuffering = false;
  } else {
    uint16_t pinValue = analogRead(mPin);
    mBuffer[mBufferIndex] = pinValue;
    mapSensorToNote();
    #if PS_DEBUG
      Serial.print("(SP) -> captureBufferValue(): wrote value to buffer: ");
      Serial.println(mBuffer[mBufferIndex]);
      Serial.print("(SP) -> mapSensorToNote(): mapped value to note: ");
      Serial.println(mNotes[mBufferIndex]);
    #endif
    mBufferIndex++;
  }
}

void SensorProxy::mapSensorToNote() {
  mNotes[mBufferIndex] = map(mBuffer[mBufferIndex],0,1023,36,95);
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ResolveRefsPass.h"

#include <boost/algorithm/string.hpp>

#include "ApiLevelChecker.h"
#include "DexUtil.h"
#include "MethodOverrideGraph.h"
#include "Resolver.h"
#include "TypeInference.h"
#include "Walkers.h"

namespace mog = method_override_graph;

namespace {

struct RefStats {
  size_t num_mref_resolved = 0;
  size_t num_fref_resolved = 0;
  size_t num_invoke_virtual_refined = 0;
  size_t num_invoke_interface_replaced = 0;
  size_t num_invoke_super_removed = 0;

  void print(PassManager* mgr) {
    TRACE(RESO, 1, "[ref reso] method ref resolved %d", num_mref_resolved);
    TRACE(RESO, 1, "[ref reso] field ref resolved %d", num_fref_resolved);
    TRACE(RESO,
          1,
          "[ref reso] invoke-virtual refined %d",
          num_invoke_virtual_refined);
    TRACE(RESO,
          1,
          "[ref reso] invoke-interface replaced %d",
          num_invoke_interface_replaced);
    TRACE(RESO,
          1,
          "[ref reso] invoke-super removed %d",
          num_invoke_super_removed);
    mgr->incr_metric("method_refs_resolved", num_mref_resolved);
    mgr->incr_metric("field_refs_resolved", num_fref_resolved);
    mgr->incr_metric("num_invoke_virtual_refined", num_invoke_virtual_refined);
    mgr->incr_metric("num_invoke_interface_replaced",
                     num_invoke_interface_replaced);
    mgr->incr_metric("num_invoke_super_removed", num_invoke_super_removed);
  }

  RefStats& operator+=(const RefStats& that) {
    num_mref_resolved += that.num_mref_resolved;
    num_fref_resolved += that.num_fref_resolved;
    num_invoke_virtual_refined += that.num_invoke_virtual_refined;
    num_invoke_interface_replaced += that.num_invoke_interface_replaced;
    num_invoke_super_removed += that.num_invoke_super_removed;
    return *this;
  }
};

void resolve_method_refs(IRInstruction* insn, RefStats& stats) {
  always_assert(insn->has_method());
  auto mref = insn->get_method();
  auto mdef = resolve_method(mref, opcode_to_search(insn));
  if (!mdef || mdef == mref) {
    return;
  }
  // Do not handle external refs in the simple resolve path.
  if (mdef->is_external()) {
    return;
  }
  auto cls = type_class(mdef->get_class());
  // Bail out if the def is non public external
  if (cls && cls->is_external() && !is_public(cls)) {
    return;
  }
  TRACE(RESO, 2, "Resolving %s\n\t=>%s", SHOW(mref), SHOW(mdef));
  insn->set_method(mdef);
  stats.num_mref_resolved++;
  if (cls != nullptr && !is_public(cls)) {
    set_public(cls);
  }
}

void resolve_field_refs(IRInstruction* insn,
                        FieldSearch field_search,
                        RefStats& stats) {
  const auto fref = insn->get_field();
  if (fref->is_def()) {
    return;
  }
  const auto real_ref = resolve_field(fref, field_search);
  if (real_ref && !real_ref->is_external() && real_ref != fref) {
    TRACE(RESO, 2, "Resolving %s\n\t=>%s", SHOW(fref), SHOW(real_ref));
    insn->set_field(real_ref);
    stats.num_fref_resolved++;
    auto cls = type_class(real_ref->get_class());
    always_assert(cls != nullptr);
    if (!is_public(cls)) {
      if (cls->is_external()) return;
      set_public(cls);
    }
  }
}

RefStats resolve_refs(DexMethod* method) {
  RefStats stats;
  if (!method || !method->get_code()) {
    return stats;
  }

  for (auto& mie : InstructionIterable(method->get_code())) {
    auto insn = mie.insn;
    switch (insn->opcode()) {
    case OPCODE_INVOKE_VIRTUAL:
    case OPCODE_INVOKE_SUPER:
    case OPCODE_INVOKE_INTERFACE:
    case OPCODE_INVOKE_STATIC:
      resolve_method_refs(insn, stats);
      break;
    case OPCODE_SGET:
    case OPCODE_SGET_WIDE:
    case OPCODE_SGET_OBJECT:
    case OPCODE_SGET_BOOLEAN:
    case OPCODE_SGET_BYTE:
    case OPCODE_SGET_CHAR:
    case OPCODE_SGET_SHORT:
    case OPCODE_SPUT:
    case OPCODE_SPUT_WIDE:
    case OPCODE_SPUT_OBJECT:
    case OPCODE_SPUT_BOOLEAN:
    case OPCODE_SPUT_BYTE:
    case OPCODE_SPUT_CHAR:
    case OPCODE_SPUT_SHORT:
      resolve_field_refs(insn, FieldSearch::Static, stats);
      break;
    case OPCODE_IGET:
    case OPCODE_IGET_WIDE:
    case OPCODE_IGET_OBJECT:
    case OPCODE_IGET_BOOLEAN:
    case OPCODE_IGET_BYTE:
    case OPCODE_IGET_CHAR:
    case OPCODE_IGET_SHORT:
    case OPCODE_IPUT:
    case OPCODE_IPUT_WIDE:
    case OPCODE_IPUT_OBJECT:
    case OPCODE_IPUT_BOOLEAN:
    case OPCODE_IPUT_BYTE:
    case OPCODE_IPUT_CHAR:
    case OPCODE_IPUT_SHORT:
      resolve_field_refs(insn, FieldSearch::Instance, stats);
      break;
    default:
      break;
    }
  }

  return stats;
}

void try_desuperify(const DexMethod* caller,
                    IRInstruction* insn,
                    RefStats& stats) {
  if (!is_invoke_super(insn->opcode())) {
    return;
  }
  auto cls = type_class(caller->get_class());
  if (cls == nullptr) {
    return;
  }
  // Skip if the callee is an interface default method (037).
  auto callee_cls = type_class(insn->get_method()->get_class());
  if (is_interface(callee_cls)) {
    return;
  }
  // resolve_method_ref will start its search in the superclass of :cls.
  auto callee = resolve_method_ref(cls, insn->get_method()->get_name(),
                                   insn->get_method()->get_proto(),
                                   MethodSearch::Virtual);
  // External methods may not always be final across runtime versions
  if (callee == nullptr || callee->is_external() || !is_final(callee)) {
    return;
  }

  TRACE(RESO, 5, "Desuperifying %s because %s is final", SHOW(insn),
        SHOW(callee));
  insn->set_opcode(OPCODE_INVOKE_VIRTUAL);
  stats.num_invoke_super_removed++;
}

bool is_excluded_external(const std::vector<std::string>& excluded_externals,
                          std::string name) {
  for (auto& excluded : excluded_externals) {
    if (boost::starts_with(name, excluded)) {
      return true;
    }
  }

  return false;
}

boost::optional<DexMethod*> get_inferred_method_def(
    const std::vector<std::string>& excluded_externals,
    const bool is_support_lib,
    DexMethod* callee,
    const DexType* inferred_type) {

  auto inferred_cls = type_class(inferred_type);
  if (!inferred_cls || is_interface(inferred_cls)) {
    return boost::none;
  }
  auto resolved = resolve_method(inferred_cls, callee->get_name(),
                                 callee->get_proto(), MethodSearch::Virtual);
  // 1. If the resolved target is excluded, we bail.
  if (!resolved || !resolved->is_def() ||
      is_excluded_external(excluded_externals, show(resolved))) {
    return boost::none;
  }

  // 2. If it's an exact match, we take the resolved target.
  // 3. If not an exact match and if it's not referenced in support libraries,
  // we take the resolved target.
  if (resolved->get_class() == inferred_type || !is_support_lib) {
    TRACE(RESO, 2, "Inferred to %s for type %s", SHOW(resolved),
          SHOW(inferred_type));
    return boost::optional<DexMethod*>(const_cast<DexMethod*>(resolved));
  }

  return boost::none;
}

RefStats refine_virtual_callsites(
    const bool resolve_to_external,
    const std::vector<std::string>& excluded_externals,
    DexMethod* method,
    bool desuperify) {
  RefStats stats;
  if (!method || !method->get_code()) {
    return stats;
  }

  auto* code = method->get_code();
  code->build_cfg(/* editable */ false);
  auto& cfg = code->cfg();
  type_inference::TypeInference inference(cfg);
  inference.run(method);
  auto& envs = inference.get_type_environments();
  auto is_support_lib = api::is_support_lib_type(method->get_class());

  for (auto& mie : InstructionIterable(code)) {
    IRInstruction* insn = mie.insn;
    if (desuperify) {
      try_desuperify(method, insn, stats);
    }

    auto opcode = insn->opcode();
    if (!is_invoke_virtual(opcode) && !is_invoke_interface(opcode)) {
      continue;
    }

    auto callee = resolve_method(insn->get_method(), opcode_to_search(insn));
    if (!callee) {
      continue;
    }

    auto this_reg = insn->src(0);
    auto& env = envs.at(insn);
    auto dex_type = env.get_dex_type(this_reg);

    if (dex_type && callee->get_class() != *dex_type) {
      // replace it with the actual implementation if any provided.
      auto m_def = get_inferred_method_def(excluded_externals, is_support_lib,
                                           callee, *dex_type);
      if (!m_def) {
        continue;
      }
      // Stop if the resolve_to_external config is False.
      auto def_meth = *m_def;
      auto def_cls = type_class((def_meth)->get_class());
      if (def_cls && !resolve_to_external && def_cls->is_external()) {
        TRACE(RESO, 4, "Bailed on external %s", SHOW(def_meth));
        continue;
      }
      insn->set_method(def_meth);
      if (is_invoke_interface(opcode)) {
        insn->set_opcode(OPCODE_INVOKE_VIRTUAL);
        stats.num_invoke_interface_replaced++;
      } else {
        stats.num_invoke_virtual_refined++;
      }
    }
  }

  return stats;
}

} // namespace

void ResolveRefsPass::run_pass(DexStoresVector& stores,
                               ConfigFiles& /* conf */,
                               PassManager& mgr) {
  int32_t min_sdk = mgr.get_redex_options().min_sdk;
  // Disable resolution to external for API level older than 19.
  if (min_sdk < 19) {
    m_resolve_to_external = false;
    TRACE(RESO, 2, "Disabling resolution to external for min_sdk %d", min_sdk);
  }

  Scope scope = build_class_scope(stores);
  RefStats stats =
      walk::parallel::methods<RefStats>(scope, [&](DexMethod* method) {
        auto local_stats = resolve_refs(method);
        local_stats += refine_virtual_callsites(
            m_resolve_to_external, m_excluded_externals, method, m_desuperify);
        return local_stats;
      });
  stats.print(&mgr);
}

static ResolveRefsPass s_pass;
<commit_msg>Adjust vmethod resolution logic<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ResolveRefsPass.h"

#include <boost/algorithm/string.hpp>

#include "ApiLevelChecker.h"
#include "DexUtil.h"
#include "MethodOverrideGraph.h"
#include "Resolver.h"
#include "TypeInference.h"
#include "Walkers.h"

namespace mog = method_override_graph;

namespace {

struct RefStats {
  size_t num_mref_resolved = 0;
  size_t num_fref_resolved = 0;
  size_t num_invoke_virtual_refined = 0;
  size_t num_invoke_interface_replaced = 0;
  size_t num_invoke_super_removed = 0;

  void print(PassManager* mgr) {
    TRACE(RESO, 1, "[ref reso] method ref resolved %d", num_mref_resolved);
    TRACE(RESO, 1, "[ref reso] field ref resolved %d", num_fref_resolved);
    TRACE(RESO,
          1,
          "[ref reso] invoke-virtual refined %d",
          num_invoke_virtual_refined);
    TRACE(RESO,
          1,
          "[ref reso] invoke-interface replaced %d",
          num_invoke_interface_replaced);
    TRACE(RESO,
          1,
          "[ref reso] invoke-super removed %d",
          num_invoke_super_removed);
    mgr->incr_metric("method_refs_resolved", num_mref_resolved);
    mgr->incr_metric("field_refs_resolved", num_fref_resolved);
    mgr->incr_metric("num_invoke_virtual_refined", num_invoke_virtual_refined);
    mgr->incr_metric("num_invoke_interface_replaced",
                     num_invoke_interface_replaced);
    mgr->incr_metric("num_invoke_super_removed", num_invoke_super_removed);
  }

  RefStats& operator+=(const RefStats& that) {
    num_mref_resolved += that.num_mref_resolved;
    num_fref_resolved += that.num_fref_resolved;
    num_invoke_virtual_refined += that.num_invoke_virtual_refined;
    num_invoke_interface_replaced += that.num_invoke_interface_replaced;
    num_invoke_super_removed += that.num_invoke_super_removed;
    return *this;
  }
};

void resolve_method_refs(IRInstruction* insn, RefStats& stats) {
  always_assert(insn->has_method());
  auto mref = insn->get_method();
  auto mdef = resolve_method(mref, opcode_to_search(insn));
  if (!mdef || mdef == mref) {
    return;
  }
  // Do not handle external refs in the simple resolve path.
  if (mdef->is_external()) {
    return;
  }
  auto cls = type_class(mdef->get_class());
  // Bail out if the def is non public external
  if (cls && cls->is_external() && !is_public(cls)) {
    return;
  }
  TRACE(RESO, 2, "Resolving %s\n\t=>%s", SHOW(mref), SHOW(mdef));
  insn->set_method(mdef);
  stats.num_mref_resolved++;
  if (cls != nullptr && !is_public(cls)) {
    set_public(cls);
  }
}

void resolve_field_refs(IRInstruction* insn,
                        FieldSearch field_search,
                        RefStats& stats) {
  const auto fref = insn->get_field();
  if (fref->is_def()) {
    return;
  }
  const auto real_ref = resolve_field(fref, field_search);
  if (real_ref && !real_ref->is_external() && real_ref != fref) {
    TRACE(RESO, 2, "Resolving %s\n\t=>%s", SHOW(fref), SHOW(real_ref));
    insn->set_field(real_ref);
    stats.num_fref_resolved++;
    auto cls = type_class(real_ref->get_class());
    always_assert(cls != nullptr);
    if (!is_public(cls)) {
      if (cls->is_external()) return;
      set_public(cls);
    }
  }
}

RefStats resolve_refs(DexMethod* method) {
  RefStats stats;
  if (!method || !method->get_code()) {
    return stats;
  }

  for (auto& mie : InstructionIterable(method->get_code())) {
    auto insn = mie.insn;
    switch (insn->opcode()) {
    case OPCODE_INVOKE_VIRTUAL:
    case OPCODE_INVOKE_SUPER:
    case OPCODE_INVOKE_INTERFACE:
    case OPCODE_INVOKE_STATIC:
      resolve_method_refs(insn, stats);
      break;
    case OPCODE_SGET:
    case OPCODE_SGET_WIDE:
    case OPCODE_SGET_OBJECT:
    case OPCODE_SGET_BOOLEAN:
    case OPCODE_SGET_BYTE:
    case OPCODE_SGET_CHAR:
    case OPCODE_SGET_SHORT:
    case OPCODE_SPUT:
    case OPCODE_SPUT_WIDE:
    case OPCODE_SPUT_OBJECT:
    case OPCODE_SPUT_BOOLEAN:
    case OPCODE_SPUT_BYTE:
    case OPCODE_SPUT_CHAR:
    case OPCODE_SPUT_SHORT:
      resolve_field_refs(insn, FieldSearch::Static, stats);
      break;
    case OPCODE_IGET:
    case OPCODE_IGET_WIDE:
    case OPCODE_IGET_OBJECT:
    case OPCODE_IGET_BOOLEAN:
    case OPCODE_IGET_BYTE:
    case OPCODE_IGET_CHAR:
    case OPCODE_IGET_SHORT:
    case OPCODE_IPUT:
    case OPCODE_IPUT_WIDE:
    case OPCODE_IPUT_OBJECT:
    case OPCODE_IPUT_BOOLEAN:
    case OPCODE_IPUT_BYTE:
    case OPCODE_IPUT_CHAR:
    case OPCODE_IPUT_SHORT:
      resolve_field_refs(insn, FieldSearch::Instance, stats);
      break;
    default:
      break;
    }
  }

  return stats;
}

void try_desuperify(const DexMethod* caller,
                    IRInstruction* insn,
                    RefStats& stats) {
  if (!is_invoke_super(insn->opcode())) {
    return;
  }
  auto cls = type_class(caller->get_class());
  if (cls == nullptr) {
    return;
  }
  // Skip if the callee is an interface default method (037).
  auto callee_cls = type_class(insn->get_method()->get_class());
  if (is_interface(callee_cls)) {
    return;
  }
  // resolve_method_ref will start its search in the superclass of :cls.
  auto callee = resolve_method_ref(cls, insn->get_method()->get_name(),
                                   insn->get_method()->get_proto(),
                                   MethodSearch::Virtual);
  // External methods may not always be final across runtime versions
  if (callee == nullptr || callee->is_external() || !is_final(callee)) {
    return;
  }

  TRACE(RESO, 5, "Desuperifying %s because %s is final", SHOW(insn),
        SHOW(callee));
  insn->set_opcode(OPCODE_INVOKE_VIRTUAL);
  stats.num_invoke_super_removed++;
}

bool is_excluded_external(const std::vector<std::string>& excluded_externals,
                          std::string name) {
  for (auto& excluded : excluded_externals) {
    if (boost::starts_with(name, excluded)) {
      return true;
    }
  }

  return false;
}

boost::optional<DexMethod*> get_inferred_method_def(
    const std::vector<std::string>& excluded_externals,
    const bool is_support_lib,
    DexMethod* callee,
    const DexType* inferred_type) {

  auto inferred_cls = type_class(inferred_type);
  if (!inferred_cls || is_interface(inferred_cls)) {
    return boost::none;
  }
  auto resolved = resolve_method(inferred_cls, callee->get_name(),
                                 callee->get_proto(), MethodSearch::Virtual);
  if (!resolved || !resolved->is_def()) {
    return boost::none;
  }
  auto resolved_cls = type_class(resolved->get_class());
  bool is_external = resolved_cls && resolved_cls->is_external();
  // 1. If the resolved target is an excluded external, we bail.
  if (is_external && is_excluded_external(excluded_externals, show(resolved))) {
    TRACE(RESO, 4, "Bailed on excluded external%s", SHOW(resolved));
    return boost::none;
  }

  // 2. If the resolved target is external and is referenced in support
  // libraries, we bail.
  if (is_external && api::is_android_sdk_type(resolved->get_class()) &&
      is_support_lib) {
    TRACE(RESO, 4, "Bailed on external in support lib %s", SHOW(resolved));
    return boost::none;
  }

  TRACE(RESO, 2, "Inferred to %s for type %s", SHOW(resolved),
        SHOW(inferred_type));
  return boost::optional<DexMethod*>(const_cast<DexMethod*>(resolved));
}

RefStats refine_virtual_callsites(
    const bool resolve_to_external,
    const std::vector<std::string>& excluded_externals,
    DexMethod* method,
    bool desuperify) {
  RefStats stats;
  if (!method || !method->get_code()) {
    return stats;
  }

  auto* code = method->get_code();
  code->build_cfg(/* editable */ false);
  auto& cfg = code->cfg();
  type_inference::TypeInference inference(cfg);
  inference.run(method);
  auto& envs = inference.get_type_environments();
  auto is_support_lib = api::is_support_lib_type(method->get_class());

  for (auto& mie : InstructionIterable(code)) {
    IRInstruction* insn = mie.insn;
    if (desuperify) {
      try_desuperify(method, insn, stats);
    }

    auto opcode = insn->opcode();
    if (!is_invoke_virtual(opcode) && !is_invoke_interface(opcode)) {
      continue;
    }

    auto callee = resolve_method(insn->get_method(), opcode_to_search(insn));
    if (!callee) {
      continue;
    }

    auto this_reg = insn->src(0);
    auto& env = envs.at(insn);
    auto dex_type = env.get_dex_type(this_reg);

    if (dex_type && callee->get_class() != *dex_type) {
      // replace it with the actual implementation if any provided.
      auto m_def = get_inferred_method_def(excluded_externals, is_support_lib,
                                           callee, *dex_type);
      if (!m_def) {
        continue;
      }
      // Stop if the resolve_to_external config is False.
      auto def_meth = *m_def;
      auto def_cls = type_class((def_meth)->get_class());
      if (def_cls && !resolve_to_external && def_cls->is_external()) {
        TRACE(RESO, 4, "Bailed on external %s", SHOW(def_meth));
        continue;
      }
      insn->set_method(def_meth);
      if (is_invoke_interface(opcode)) {
        insn->set_opcode(OPCODE_INVOKE_VIRTUAL);
        stats.num_invoke_interface_replaced++;
      } else {
        stats.num_invoke_virtual_refined++;
      }
    }
  }

  return stats;
}

} // namespace

void ResolveRefsPass::run_pass(DexStoresVector& stores,
                               ConfigFiles& /* conf */,
                               PassManager& mgr) {
  int32_t min_sdk = mgr.get_redex_options().min_sdk;
  // Disable resolution to external for API level older than 19.
  if (min_sdk < 19) {
    m_resolve_to_external = false;
    TRACE(RESO, 2, "Disabling resolution to external for min_sdk %d", min_sdk);
  }

  Scope scope = build_class_scope(stores);
  RefStats stats =
      walk::parallel::methods<RefStats>(scope, [&](DexMethod* method) {
        auto local_stats = resolve_refs(method);
        local_stats += refine_virtual_callsites(
            m_resolve_to_external, m_excluded_externals, method, m_desuperify);
        return local_stats;
      });
  stats.print(&mgr);
}

static ResolveRefsPass s_pass;
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "ShowEpisode.h"
#include "database/SqliteTools.h"
#include "database/SqliteQuery.h"
#include "Show.h"
#include "Media.h"

namespace medialibrary
{

const std::string ShowEpisode::Table::Name = "ShowEpisode";
const std::string ShowEpisode::Table::PrimaryKeyColumn = "id_episode";
int64_t ShowEpisode::* const ShowEpisode::Table::PrimaryKey = &ShowEpisode::m_id;

ShowEpisode::ShowEpisode( MediaLibraryPtr ml, sqlite::Row& row )
    : m_ml( ml )
    , m_id( row.extract<decltype(m_id)>() )
    , m_mediaId( row.extract<decltype(m_mediaId)>() )
    , m_episodeId( row.extract<decltype(m_episodeId)>() )
    , m_seasonId( row.extract<decltype(m_seasonId)>() )
    , m_shortSummary( row.extract<decltype(m_shortSummary)>() )
    , m_tvdbId( row.extract<decltype(m_tvdbId)>() )
    , m_showId( row.extract<decltype(m_showId)>() )
{
    assert( row.hasRemainingColumns() == false );
}

ShowEpisode::ShowEpisode( MediaLibraryPtr ml, int64_t mediaId, uint32_t seasonId,
                          uint32_t episodeNumber, int64_t showId )
    : m_ml( ml )
    , m_id( 0 )
    , m_mediaId( mediaId )
    , m_episodeId( episodeNumber )
    , m_seasonId( seasonId )
    , m_showId( showId )
{
}

int64_t ShowEpisode::id() const
{
    return m_id;
}

unsigned int ShowEpisode::episodeId() const
{
    return m_episodeId;
}

unsigned int ShowEpisode::seasonId() const
{
    return m_seasonId;
}

const std::string& ShowEpisode::shortSummary() const
{
    return m_shortSummary;
}

bool ShowEpisode::setShortSummary( const std::string& summary )
{
    static const std::string req = "UPDATE " + ShowEpisode::Table::Name
            + " SET episode_summary = ? WHERE id_episode = ?";
    if ( sqlite::Tools::executeUpdate( m_ml->getConn(), req, summary, m_id ) == false )
        return false;
    m_shortSummary = summary;
    return true;
}

const std::string& ShowEpisode::tvdbId() const
{
    return m_tvdbId;
}

bool ShowEpisode::setTvdbId( const std::string& tvdbId )
{
    static const std::string req = "UPDATE " + ShowEpisode::Table::Name
            + " SET tvdb_id = ? WHERE id_episode = ?";
    if ( sqlite::Tools::executeUpdate( m_ml->getConn(), req, tvdbId, m_id ) == false )
        return false;
    m_tvdbId = tvdbId;
    return true;
}

std::shared_ptr<IShow> ShowEpisode::show()
{
    if ( m_show == nullptr && m_showId != 0 )
    {
        m_show = Show::fetch( m_ml, m_showId );
    }
    return m_show;
}

void ShowEpisode::createTable( sqlite::Connection* dbConnection )
{
    sqlite::Tools::executeRequest( dbConnection,
                                   schema( Table::Name, Settings::DbModelVersion ) );
}

void ShowEpisode::createIndexes( sqlite::Connection* dbConnection )
{
    sqlite::Tools::executeRequest( dbConnection,
                                   index( Indexes::MediaIdShowId, Settings::DbModelVersion ) );
}

std::string ShowEpisode::schema( const std::string& tableName, uint32_t )
{
    assert( tableName == Table::Name );
    return "CREATE TABLE " + Table::Name +
    "("
        "id_episode INTEGER PRIMARY KEY AUTOINCREMENT,"
        "media_id UNSIGNED INTEGER NOT NULL,"
        "episode_number UNSIGNED INT,"
        "season_number UNSIGNED INT,"
        "episode_summary TEXT,"
        "tvdb_id TEXT,"
        "show_id UNSIGNED INT,"
        "FOREIGN KEY(media_id) REFERENCES " + Media::Table::Name
            + "(id_media) ON DELETE CASCADE,"
        "FOREIGN KEY(show_id) REFERENCES " + Show::Table::Name
            + "(id_show) ON DELETE CASCADE"
    ")";
}

std::string ShowEpisode::index( Indexes index, uint32_t dbModel )
{
    assert( index == Indexes::MediaIdShowId );
    return "CREATE INDEX " + indexName( index, dbModel ) +
           " ON " + Table::Name + "(media_id, show_id)";
}

std::string ShowEpisode::indexName( Indexes index, uint32_t )
{
    assert( index == Indexes::MediaIdShowId );
    return "show_episode_media_show_idx";
}

bool ShowEpisode::checkDbModel(MediaLibraryPtr ml)
{
    return sqlite::Tools::checkTableSchema( ml->getConn(),
                                       schema( Table::Name, Settings::DbModelVersion ),
                                       Table::Name );
}

std::shared_ptr<ShowEpisode> ShowEpisode::create( MediaLibraryPtr ml,
                                                  int64_t mediaId,
                                                  uint32_t seasonId,
                                                  uint32_t episodeId,
                                                  int64_t showId )
{
    auto episode = std::make_shared<ShowEpisode>( ml, mediaId, seasonId, episodeId,
                                                  showId );
    static const std::string req = "INSERT INTO " + ShowEpisode::Table::Name
            + "(media_id, episode_number, season_number, show_id) VALUES(?, ?, ?, ?)";
    if ( insert( ml, episode, req, mediaId, episodeId, seasonId, showId ) == false )
        return nullptr;
    return episode;
}

ShowEpisodePtr ShowEpisode::fromMedia( MediaLibraryPtr ml, int64_t mediaId )
{
    static const std::string req = "SELECT * FROM " + ShowEpisode::Table::Name + " WHERE media_id = ?";
    return fetch( ml, req, mediaId );
}

}
<commit_msg>ShowEpisode: Check index as part of integrity checks<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "ShowEpisode.h"
#include "database/SqliteTools.h"
#include "database/SqliteQuery.h"
#include "Show.h"
#include "Media.h"

namespace medialibrary
{

const std::string ShowEpisode::Table::Name = "ShowEpisode";
const std::string ShowEpisode::Table::PrimaryKeyColumn = "id_episode";
int64_t ShowEpisode::* const ShowEpisode::Table::PrimaryKey = &ShowEpisode::m_id;

ShowEpisode::ShowEpisode( MediaLibraryPtr ml, sqlite::Row& row )
    : m_ml( ml )
    , m_id( row.extract<decltype(m_id)>() )
    , m_mediaId( row.extract<decltype(m_mediaId)>() )
    , m_episodeId( row.extract<decltype(m_episodeId)>() )
    , m_seasonId( row.extract<decltype(m_seasonId)>() )
    , m_shortSummary( row.extract<decltype(m_shortSummary)>() )
    , m_tvdbId( row.extract<decltype(m_tvdbId)>() )
    , m_showId( row.extract<decltype(m_showId)>() )
{
    assert( row.hasRemainingColumns() == false );
}

ShowEpisode::ShowEpisode( MediaLibraryPtr ml, int64_t mediaId, uint32_t seasonId,
                          uint32_t episodeNumber, int64_t showId )
    : m_ml( ml )
    , m_id( 0 )
    , m_mediaId( mediaId )
    , m_episodeId( episodeNumber )
    , m_seasonId( seasonId )
    , m_showId( showId )
{
}

int64_t ShowEpisode::id() const
{
    return m_id;
}

unsigned int ShowEpisode::episodeId() const
{
    return m_episodeId;
}

unsigned int ShowEpisode::seasonId() const
{
    return m_seasonId;
}

const std::string& ShowEpisode::shortSummary() const
{
    return m_shortSummary;
}

bool ShowEpisode::setShortSummary( const std::string& summary )
{
    static const std::string req = "UPDATE " + ShowEpisode::Table::Name
            + " SET episode_summary = ? WHERE id_episode = ?";
    if ( sqlite::Tools::executeUpdate( m_ml->getConn(), req, summary, m_id ) == false )
        return false;
    m_shortSummary = summary;
    return true;
}

const std::string& ShowEpisode::tvdbId() const
{
    return m_tvdbId;
}

bool ShowEpisode::setTvdbId( const std::string& tvdbId )
{
    static const std::string req = "UPDATE " + ShowEpisode::Table::Name
            + " SET tvdb_id = ? WHERE id_episode = ?";
    if ( sqlite::Tools::executeUpdate( m_ml->getConn(), req, tvdbId, m_id ) == false )
        return false;
    m_tvdbId = tvdbId;
    return true;
}

std::shared_ptr<IShow> ShowEpisode::show()
{
    if ( m_show == nullptr && m_showId != 0 )
    {
        m_show = Show::fetch( m_ml, m_showId );
    }
    return m_show;
}

void ShowEpisode::createTable( sqlite::Connection* dbConnection )
{
    sqlite::Tools::executeRequest( dbConnection,
                                   schema( Table::Name, Settings::DbModelVersion ) );
}

void ShowEpisode::createIndexes( sqlite::Connection* dbConnection )
{
    sqlite::Tools::executeRequest( dbConnection,
                                   index( Indexes::MediaIdShowId, Settings::DbModelVersion ) );
}

std::string ShowEpisode::schema( const std::string& tableName, uint32_t )
{
    assert( tableName == Table::Name );
    return "CREATE TABLE " + Table::Name +
    "("
        "id_episode INTEGER PRIMARY KEY AUTOINCREMENT,"
        "media_id UNSIGNED INTEGER NOT NULL,"
        "episode_number UNSIGNED INT,"
        "season_number UNSIGNED INT,"
        "episode_summary TEXT,"
        "tvdb_id TEXT,"
        "show_id UNSIGNED INT,"
        "FOREIGN KEY(media_id) REFERENCES " + Media::Table::Name
            + "(id_media) ON DELETE CASCADE,"
        "FOREIGN KEY(show_id) REFERENCES " + Show::Table::Name
            + "(id_show) ON DELETE CASCADE"
    ")";
}

std::string ShowEpisode::index( Indexes index, uint32_t dbModel )
{
    assert( index == Indexes::MediaIdShowId );
    return "CREATE INDEX " + indexName( index, dbModel ) +
           " ON " + Table::Name + "(media_id, show_id)";
}

std::string ShowEpisode::indexName( Indexes index, uint32_t )
{
    assert( index == Indexes::MediaIdShowId );
    return "show_episode_media_show_idx";
}

bool ShowEpisode::checkDbModel(MediaLibraryPtr ml)
{
    return sqlite::Tools::checkTableSchema( ml->getConn(),
                                       schema( Table::Name, Settings::DbModelVersion ),
                                       Table::Name ) &&
           sqlite::Tools::checkIndexStatement( ml->getConn(),
                index( Indexes::MediaIdShowId, Settings::DbModelVersion ),
                indexName( Indexes::MediaIdShowId, Settings::DbModelVersion ) );
}

std::shared_ptr<ShowEpisode> ShowEpisode::create( MediaLibraryPtr ml,
                                                  int64_t mediaId,
                                                  uint32_t seasonId,
                                                  uint32_t episodeId,
                                                  int64_t showId )
{
    auto episode = std::make_shared<ShowEpisode>( ml, mediaId, seasonId, episodeId,
                                                  showId );
    static const std::string req = "INSERT INTO " + ShowEpisode::Table::Name
            + "(media_id, episode_number, season_number, show_id) VALUES(?, ?, ?, ?)";
    if ( insert( ml, episode, req, mediaId, episodeId, seasonId, showId ) == false )
        return nullptr;
    return episode;
}

ShowEpisodePtr ShowEpisode::fromMedia( MediaLibraryPtr ml, int64_t mediaId )
{
    static const std::string req = "SELECT * FROM " + ShowEpisode::Table::Name + " WHERE media_id = ?";
    return fetch( ml, req, mediaId );
}

}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

/**
 * \file ir_function_inlining.cpp
 *
 * Replaces calls to functions with the body of the function.
 */

#include <inttypes.h>
#include "ir.h"
#include "ir_visitor.h"
#include "ir_function_inlining.h"
#include "ir_expression_flattening.h"
#include "glsl_types.h"
#include "program/hash_table.h"

static void
do_sampler_replacement(exec_list *instructions,
		       ir_variable *sampler,
		       ir_dereference *deref);

class ir_function_inlining_visitor : public ir_hierarchical_visitor {
public:
   ir_function_inlining_visitor()
   {
      progress = false;
   }

   virtual ~ir_function_inlining_visitor()
   {
      /* empty */
   }

   virtual ir_visitor_status visit_enter(ir_expression *);
   virtual ir_visitor_status visit_enter(ir_call *);
   virtual ir_visitor_status visit_enter(ir_assignment *);
   virtual ir_visitor_status visit_enter(ir_return *);
   virtual ir_visitor_status visit_enter(ir_texture *);
   virtual ir_visitor_status visit_enter(ir_swizzle *);

   bool progress;
};

bool
automatic_inlining_predicate(ir_instruction *ir)
{
   ir_call *call = ir->as_call();

   if (call && can_inline(call))
      return true;

   return false;
}

bool
do_function_inlining(exec_list *instructions)
{
   ir_function_inlining_visitor v;

   do_expression_flattening(instructions, automatic_inlining_predicate);

   v.run(instructions);

   return v.progress;
}

static void
replace_return_with_assignment(ir_instruction *ir, void *data)
{
   void *ctx = talloc_parent(ir);
   ir_variable *retval = (ir_variable *)data;
   ir_return *ret = ir->as_return();

   if (ret) {
      if (ret->value) {
	 ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
	 ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
      } else {
	 /* un-valued return has to be the last return, or we shouldn't
	  * have reached here. (see can_inline()).
	  */
	 assert(ret->next->is_tail_sentinel());
	 ret->remove();
      }
   }
}

ir_rvalue *
ir_call::generate_inline(ir_instruction *next_ir)
{
   void *ctx = talloc_parent(this);
   ir_variable **parameters;
   int num_parameters;
   int i;
   ir_variable *retval = NULL;
   struct hash_table *ht;

   ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);

   num_parameters = 0;
   foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
      num_parameters++;

   parameters = new ir_variable *[num_parameters];

   /* Generate storage for the return value. */
   if (this->callee->return_type) {
      retval = new(ctx) ir_variable(this->callee->return_type, "__retval",
				    ir_var_auto);
      next_ir->insert_before(retval);
   }

   /* Generate the declarations for the parameters to our inlined code,
    * and set up the mapping of real function body variables to ours.
    */
   i = 0;
   exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
   exec_list_iterator param_iter = this->actual_parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
      ir_rvalue *param = (ir_rvalue *) param_iter.get();

      /* Generate a new variable for the parameter. */
      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
	 /* For samplers, we want the inlined sampler references
	  * referencing the passed in sampler variable, since that
	  * will have the location information, which an assignment of
	  * a sampler wouldn't.  Fix it up below.
	  */
	 parameters[i] = NULL;
      } else {
	 parameters[i] = sig_param->clone(ctx, ht);
	 parameters[i]->mode = ir_var_auto;
	 next_ir->insert_before(parameters[i]);
      }

      /* Move the actual param into our param variable if it's an 'in' type. */
      if (parameters[i] && (sig_param->mode == ir_var_in ||
			    sig_param->mode == ir_var_inout)) {
	 ir_assignment *assign;

	 assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
					 param, NULL);
	 next_ir->insert_before(assign);
      }

      sig_param_iter.next();
      param_iter.next();
   }

   exec_list new_instructions;

   /* Generate the inlined body of the function to a new list */
   foreach_iter(exec_list_iterator, iter, callee->body) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      ir_instruction *new_ir = ir->clone(ctx, ht);

      new_instructions.push_tail(new_ir);
      visit_tree(new_ir, replace_return_with_assignment, retval);
   }

   /* If any samplers were passed in, replace any deref of the sampler
    * with a deref of the sampler argument.
    */
   param_iter = this->actual_parameters.iterator();
   sig_param_iter = this->callee->parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_instruction *const param = (ir_instruction *) param_iter.get();
      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();

      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
	 ir_dereference *deref = param->as_dereference();

	 assert(deref);
	 do_sampler_replacement(&new_instructions, sig_param, deref);
      }
   }

   /* Now push those new instructions in. */
   foreach_iter(exec_list_iterator, iter, new_instructions) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      next_ir->insert_before(ir);
   }

   /* Copy back the value of any 'out' parameters from the function body
    * variables to our own.
    */
   i = 0;
   param_iter = this->actual_parameters.iterator();
   sig_param_iter = this->callee->parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_instruction *const param = (ir_instruction *) param_iter.get();
      const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();

      /* Move our param variable into the actual param if it's an 'out' type. */
      if (parameters[i] && (sig_param->mode == ir_var_out ||
			    sig_param->mode == ir_var_inout)) {
	 ir_assignment *assign;

	 assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
					 new(ctx) ir_dereference_variable(parameters[i]),
					 NULL);
	 next_ir->insert_before(assign);
      }

      param_iter.next();
      sig_param_iter.next();
   }

   delete [] parameters;

   hash_table_dtor(ht);

   if (retval)
      return new(ctx) ir_dereference_variable(retval);
   else
      return NULL;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_expression *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_return *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_texture *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_call *ir)
{
   if (can_inline(ir)) {
      /* If the call was part of some tree, then it should have been
       * flattened out or we shouldn't have seen it because of a
       * visit_continue_with_parent in this visitor.
       */
      assert(ir == base_ir);

      (void) ir->generate_inline(ir);
      ir->remove();
      this->progress = true;
   }

   return visit_continue;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
{
   ir_call *call = ir->rhs->as_call();
   if (!call || !can_inline(call))
      return visit_continue;

   /* generates the parameter setup, function body, and returns the return
    * value of the function
    */
   ir_rvalue *rhs = call->generate_inline(ir);
   assert(rhs);

   ir->rhs = rhs;
   this->progress = true;

   return visit_continue;
}

/**
 * Replaces references to the "sampler" variable with a clone of "deref."
 *
 * From the spec, samplers can appear in the tree as function
 * (non-out) parameters and as the result of array indexing and
 * structure field selection.  In our builtin implementation, they
 * also appear in the sampler field of an ir_tex instruction.
 */

class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
public:
   ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
   {
      this->sampler = sampler;
      this->deref = deref;
   }

   virtual ~ir_sampler_replacement_visitor()
   {
   }

   virtual ir_visitor_status visit_leave(ir_call *);
   virtual ir_visitor_status visit_leave(ir_dereference_array *);
   virtual ir_visitor_status visit_leave(ir_dereference_record *);
   virtual ir_visitor_status visit_leave(ir_texture *);

   void replace_deref(ir_dereference **deref);
   void replace_rvalue(ir_rvalue **rvalue);

   ir_variable *sampler;
   ir_dereference *deref;
};

void
ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
{
   ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
   if (deref_var && deref_var->var == this->sampler) {
      *deref = this->deref->clone(talloc_parent(*deref), NULL);
   }
}

void
ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_dereference *deref = (*rvalue)->as_dereference();

   if (!deref)
      return;

   replace_deref(&deref);
   *rvalue = deref;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
{
   replace_deref(&ir->sampler);

   return visit_continue;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
{
   replace_rvalue(&ir->array);
   return visit_continue;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
{
   replace_rvalue(&ir->record);
   return visit_continue;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
{
   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *param = (ir_rvalue *)iter.get();
      ir_rvalue *new_param = param;
      replace_rvalue(&new_param);

      if (new_param != param) {
	 param->replace_with(new_param);
      }
   }
   return visit_continue;
}

static void
do_sampler_replacement(exec_list *instructions,
		       ir_variable *sampler,
		       ir_dereference *deref)
{
   ir_sampler_replacement_visitor v(sampler, deref);

   visit_list_elements(&v, instructions);
}
<commit_msg>ir_function_inlining: Fix missing iter.next() in inlining sampler params.<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

/**
 * \file ir_function_inlining.cpp
 *
 * Replaces calls to functions with the body of the function.
 */

#include <inttypes.h>
#include "ir.h"
#include "ir_visitor.h"
#include "ir_function_inlining.h"
#include "ir_expression_flattening.h"
#include "glsl_types.h"
#include "program/hash_table.h"

static void
do_sampler_replacement(exec_list *instructions,
		       ir_variable *sampler,
		       ir_dereference *deref);

class ir_function_inlining_visitor : public ir_hierarchical_visitor {
public:
   ir_function_inlining_visitor()
   {
      progress = false;
   }

   virtual ~ir_function_inlining_visitor()
   {
      /* empty */
   }

   virtual ir_visitor_status visit_enter(ir_expression *);
   virtual ir_visitor_status visit_enter(ir_call *);
   virtual ir_visitor_status visit_enter(ir_assignment *);
   virtual ir_visitor_status visit_enter(ir_return *);
   virtual ir_visitor_status visit_enter(ir_texture *);
   virtual ir_visitor_status visit_enter(ir_swizzle *);

   bool progress;
};

bool
automatic_inlining_predicate(ir_instruction *ir)
{
   ir_call *call = ir->as_call();

   if (call && can_inline(call))
      return true;

   return false;
}

bool
do_function_inlining(exec_list *instructions)
{
   ir_function_inlining_visitor v;

   do_expression_flattening(instructions, automatic_inlining_predicate);

   v.run(instructions);

   return v.progress;
}

static void
replace_return_with_assignment(ir_instruction *ir, void *data)
{
   void *ctx = talloc_parent(ir);
   ir_variable *retval = (ir_variable *)data;
   ir_return *ret = ir->as_return();

   if (ret) {
      if (ret->value) {
	 ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
	 ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
      } else {
	 /* un-valued return has to be the last return, or we shouldn't
	  * have reached here. (see can_inline()).
	  */
	 assert(ret->next->is_tail_sentinel());
	 ret->remove();
      }
   }
}

ir_rvalue *
ir_call::generate_inline(ir_instruction *next_ir)
{
   void *ctx = talloc_parent(this);
   ir_variable **parameters;
   int num_parameters;
   int i;
   ir_variable *retval = NULL;
   struct hash_table *ht;

   ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);

   num_parameters = 0;
   foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
      num_parameters++;

   parameters = new ir_variable *[num_parameters];

   /* Generate storage for the return value. */
   if (this->callee->return_type) {
      retval = new(ctx) ir_variable(this->callee->return_type, "__retval",
				    ir_var_auto);
      next_ir->insert_before(retval);
   }

   /* Generate the declarations for the parameters to our inlined code,
    * and set up the mapping of real function body variables to ours.
    */
   i = 0;
   exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
   exec_list_iterator param_iter = this->actual_parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
      ir_rvalue *param = (ir_rvalue *) param_iter.get();

      /* Generate a new variable for the parameter. */
      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
	 /* For samplers, we want the inlined sampler references
	  * referencing the passed in sampler variable, since that
	  * will have the location information, which an assignment of
	  * a sampler wouldn't.  Fix it up below.
	  */
	 parameters[i] = NULL;
      } else {
	 parameters[i] = sig_param->clone(ctx, ht);
	 parameters[i]->mode = ir_var_auto;
	 next_ir->insert_before(parameters[i]);
      }

      /* Move the actual param into our param variable if it's an 'in' type. */
      if (parameters[i] && (sig_param->mode == ir_var_in ||
			    sig_param->mode == ir_var_inout)) {
	 ir_assignment *assign;

	 assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
					 param, NULL);
	 next_ir->insert_before(assign);
      }

      sig_param_iter.next();
      param_iter.next();
   }

   exec_list new_instructions;

   /* Generate the inlined body of the function to a new list */
   foreach_iter(exec_list_iterator, iter, callee->body) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      ir_instruction *new_ir = ir->clone(ctx, ht);

      new_instructions.push_tail(new_ir);
      visit_tree(new_ir, replace_return_with_assignment, retval);
   }

   /* If any samplers were passed in, replace any deref of the sampler
    * with a deref of the sampler argument.
    */
   param_iter = this->actual_parameters.iterator();
   sig_param_iter = this->callee->parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_instruction *const param = (ir_instruction *) param_iter.get();
      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();

      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
	 ir_dereference *deref = param->as_dereference();

	 assert(deref);
	 do_sampler_replacement(&new_instructions, sig_param, deref);
      }
      param_iter.next();
      sig_param_iter.next();
   }

   /* Now push those new instructions in. */
   foreach_iter(exec_list_iterator, iter, new_instructions) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      next_ir->insert_before(ir);
   }

   /* Copy back the value of any 'out' parameters from the function body
    * variables to our own.
    */
   i = 0;
   param_iter = this->actual_parameters.iterator();
   sig_param_iter = this->callee->parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_instruction *const param = (ir_instruction *) param_iter.get();
      const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();

      /* Move our param variable into the actual param if it's an 'out' type. */
      if (parameters[i] && (sig_param->mode == ir_var_out ||
			    sig_param->mode == ir_var_inout)) {
	 ir_assignment *assign;

	 assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
					 new(ctx) ir_dereference_variable(parameters[i]),
					 NULL);
	 next_ir->insert_before(assign);
      }

      param_iter.next();
      sig_param_iter.next();
   }

   delete [] parameters;

   hash_table_dtor(ht);

   if (retval)
      return new(ctx) ir_dereference_variable(retval);
   else
      return NULL;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_expression *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_return *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_texture *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_call *ir)
{
   if (can_inline(ir)) {
      /* If the call was part of some tree, then it should have been
       * flattened out or we shouldn't have seen it because of a
       * visit_continue_with_parent in this visitor.
       */
      assert(ir == base_ir);

      (void) ir->generate_inline(ir);
      ir->remove();
      this->progress = true;
   }

   return visit_continue;
}

ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
{
   ir_call *call = ir->rhs->as_call();
   if (!call || !can_inline(call))
      return visit_continue;

   /* generates the parameter setup, function body, and returns the return
    * value of the function
    */
   ir_rvalue *rhs = call->generate_inline(ir);
   assert(rhs);

   ir->rhs = rhs;
   this->progress = true;

   return visit_continue;
}

/**
 * Replaces references to the "sampler" variable with a clone of "deref."
 *
 * From the spec, samplers can appear in the tree as function
 * (non-out) parameters and as the result of array indexing and
 * structure field selection.  In our builtin implementation, they
 * also appear in the sampler field of an ir_tex instruction.
 */

class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
public:
   ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
   {
      this->sampler = sampler;
      this->deref = deref;
   }

   virtual ~ir_sampler_replacement_visitor()
   {
   }

   virtual ir_visitor_status visit_leave(ir_call *);
   virtual ir_visitor_status visit_leave(ir_dereference_array *);
   virtual ir_visitor_status visit_leave(ir_dereference_record *);
   virtual ir_visitor_status visit_leave(ir_texture *);

   void replace_deref(ir_dereference **deref);
   void replace_rvalue(ir_rvalue **rvalue);

   ir_variable *sampler;
   ir_dereference *deref;
};

void
ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
{
   ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
   if (deref_var && deref_var->var == this->sampler) {
      *deref = this->deref->clone(talloc_parent(*deref), NULL);
   }
}

void
ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_dereference *deref = (*rvalue)->as_dereference();

   if (!deref)
      return;

   replace_deref(&deref);
   *rvalue = deref;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
{
   replace_deref(&ir->sampler);

   return visit_continue;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
{
   replace_rvalue(&ir->array);
   return visit_continue;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
{
   replace_rvalue(&ir->record);
   return visit_continue;
}

ir_visitor_status
ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
{
   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *param = (ir_rvalue *)iter.get();
      ir_rvalue *new_param = param;
      replace_rvalue(&new_param);

      if (new_param != param) {
	 param->replace_with(new_param);
      }
   }
   return visit_continue;
}

static void
do_sampler_replacement(exec_list *instructions,
		       ir_variable *sampler,
		       ir_dereference *deref)
{
   ir_sampler_replacement_visitor v(sampler, deref);

   visit_list_elements(&v, instructions);
}
<|endoftext|>


<commit_before>
// WinUI.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "afxwinappex.h"
#include "afxdialogex.h"
#include "LogCC.h"
#include "MainFrm.h"
#include "ModulVer.h"
#include "ChildFrm.h"
#include "LogCCDoc.h"
#include "LogMainView.h"
#include "afxwin.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CLogCCApp

BEGIN_MESSAGE_MAP(CLogCCApp, CWinAppEx)
	ON_COMMAND(ID_APP_ABOUT, &CLogCCApp::OnAppAbout)
	//// 基于文件的标准文档命令
	ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)
END_MESSAGE_MAP()

// CLogCCApp 构造

CLogCCApp::CLogCCApp() {
	m_bHiColorIcons = TRUE;

	// 支持重新启动管理器
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
#ifdef _MANAGED
	// 如果应用程序是利用公共语言运行时支持(/clr)构建的，则:
	//     1) 必须有此附加设置，“重新启动管理器”支持才能正常工作。
	//     2) 在您的项目中，您必须按照生成顺序向 System.Windows.Forms 添加引用。
	System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
#endif

	// TODO: 将以下应用程序 ID 字符串替换为唯一的 ID 字符串；建议的字符串格式
	//为 CompanyName.ProductName.SubProduct.VersionInformation
	SetAppID(_T("WinUI.AppID.NoVersion"));

	// TODO: 在此处添加构造代码，
	// 将所有重要的初始化放置在 InitInstance 中
}

// 唯一的一个 CLogCCApp 对象

CLogCCApp theApp;

// CLogCCApp 初始化

BOOL CLogCCApp::InitInstance() {
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式，
	//则需要 InitCommonControlsEx()。否则，将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinAppEx::InitInstance();

	// 初始化 OLE 库
	if (!AfxOleInit()) {
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();

	EnableTaskbarInteraction();

	// 使用 RichEdit 控件需要  AfxInitRichEdit2()
	// AfxInitRichEdit2();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小，则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串，
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	LoadStdProfileSettings(10);  // 加载标准 INI 文件选项(包括 MRU)

	InitContextMenuManager();

	InitKeyboardManager();

	InitTooltipManager();
	CMFCToolTipInfo ttParams;
	ttParams.m_bVislManagerTheme = TRUE;
	theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
	        RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

	// 注册应用程序的文档模板。文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CMultiDocTemplate* pDocTemplate;
	pDocTemplate = new CMultiDocTemplate(IDR_LogCCTYPE,
	                                     RUNTIME_CLASS(CLogCCDoc),
	                                     RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
	                                     RUNTIME_CLASS(CLogMainView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);

	// 创建主 MDI 框架窗口
	CMainFrame* pMainFrame = new CMainFrame;
	if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) {
		delete pMainFrame;
		return FALSE;
	}
	m_pMainWnd = pMainFrame;
	// 仅当具有后缀时才调用 DragAcceptFiles
	//  在 MDI 应用程序中，这应在设置 m_pMainWnd 之后立即发生
	// 启用拖/放
	m_pMainWnd->DragAcceptFiles();

	// 分析标准 shell 命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);

	// 启用“DDE 执行”
	EnableShellOpen();
	RegisterShellFileTypes(TRUE);

	// 默认不新建文档
	cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;

	// 调度在命令行中指定的命令。如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序，则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;
	// 主窗口已初始化，因此显示它并对其进行更新
	pMainFrame->ShowWindow(m_nCmdShow);
	pMainFrame->UpdateWindow();

	return TRUE;
}

int CLogCCApp::ExitInstance() {
	//TODO: 处理可能已添加的附加资源
	AfxOleTerm(FALSE);

	return CWinAppEx::ExitInstance();
}

// CLogCCApp 消息处理程序

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx {
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL OnInitDialog();
private:
	CStatic versionDesc;
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) {
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX) {
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_VERSION_DESC, versionDesc);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// 用于运行对话框的应用程序命令
void CLogCCApp::OnAppAbout() {
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}

// CLogCCApp 自定义加载/保存方法

void CLogCCApp::PreLoadState() {
	BOOL bNameValid;
	CString strName;
	bNameValid = strName.LoadString(IDS_EDIT_MENU);
	ASSERT(bNameValid);
	GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EDIT);
}

void CLogCCApp::LoadCustomState() {
}

void CLogCCApp::SaveCustomState() {
}

// CLogCCApp 消息处理程序

BOOL CAboutDlg::OnInitDialog() {
	CDialogEx::OnInitDialog();

	TCHAR exePath[MAX_PATH];
	::GetModuleFileName(::AfxGetInstanceHandle(), exePath, MAX_PATH);

	CModuleVersion versionReader;
	versionReader.GetFileVersionInfo(exePath);

	basic_ostringstream<TCHAR> oss;
	oss << _T("LogCC ")
	    << HIWORD(versionReader.dwProductVersionMS) << _T(".")
	    << LOWORD(versionReader.dwProductVersionMS) << _T(".")
	    << HIWORD(versionReader.dwProductVersionLS) << _T(".")
	    << LOWORD(versionReader.dwProductVersionLS)
	    << _T("");
	versionDesc.SetWindowText(oss.str().c_str());

	oss.str(_T(""));

	return TRUE;  // return TRUE unless you set the focus to a control
	// 异常: OCX 属性页应返回 FALSE
}
<commit_msg>引入vld，解决两处泄露<commit_after>
// WinUI.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "afxwinappex.h"
#include "afxdialogex.h"
#include "LogCC.h"
#include "MainFrm.h"
#include "ModulVer.h"
#include "ChildFrm.h"
#include "LogCCDoc.h"
#include "LogMainView.h"
#include "afxwin.h"
#include "LogPainterFactory.h"
#include "ModelFactory.h"

#ifdef _DEBUG
#include <vld.h>
#endif // _DEBUG

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CLogCCApp

BEGIN_MESSAGE_MAP(CLogCCApp, CWinAppEx)
	ON_COMMAND(ID_APP_ABOUT, &CLogCCApp::OnAppAbout)
	//// 基于文件的标准文档命令
	ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)
END_MESSAGE_MAP()

// CLogCCApp 构造

CLogCCApp::CLogCCApp() {
	m_bHiColorIcons = TRUE;

	// 支持重新启动管理器
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
#ifdef _MANAGED
	// 如果应用程序是利用公共语言运行时支持(/clr)构建的，则:
	//     1) 必须有此附加设置，“重新启动管理器”支持才能正常工作。
	//     2) 在您的项目中，您必须按照生成顺序向 System.Windows.Forms 添加引用。
	System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
#endif

	// TODO: 将以下应用程序 ID 字符串替换为唯一的 ID 字符串；建议的字符串格式
	//为 CompanyName.ProductName.SubProduct.VersionInformation
	SetAppID(_T("WinUI.AppID.NoVersion"));

	// TODO: 在此处添加构造代码，
	// 将所有重要的初始化放置在 InitInstance 中
}

// 唯一的一个 CLogCCApp 对象

CLogCCApp theApp;

// CLogCCApp 初始化

BOOL CLogCCApp::InitInstance() {
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式，
	//则需要 InitCommonControlsEx()。否则，将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinAppEx::InitInstance();

	// 初始化 OLE 库
	if (!AfxOleInit()) {
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();

	EnableTaskbarInteraction();

	// 使用 RichEdit 控件需要  AfxInitRichEdit2()
	// AfxInitRichEdit2();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小，则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串，
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	LoadStdProfileSettings(10);  // 加载标准 INI 文件选项(包括 MRU)

	InitContextMenuManager();

	InitKeyboardManager();

	InitTooltipManager();
	CMFCToolTipInfo ttParams;
	ttParams.m_bVislManagerTheme = TRUE;
	theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
	        RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

	// 注册应用程序的文档模板。文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CMultiDocTemplate* pDocTemplate;
	pDocTemplate = new CMultiDocTemplate(IDR_LogCCTYPE,
	                                     RUNTIME_CLASS(CLogCCDoc),
	                                     RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
	                                     RUNTIME_CLASS(CLogMainView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);

	// 创建主 MDI 框架窗口
	CMainFrame* pMainFrame = new CMainFrame;
	if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) {
		delete pMainFrame;
		return FALSE;
	}
	m_pMainWnd = pMainFrame;
	// 仅当具有后缀时才调用 DragAcceptFiles
	//  在 MDI 应用程序中，这应在设置 m_pMainWnd 之后立即发生
	// 启用拖/放
	m_pMainWnd->DragAcceptFiles();

	// 分析标准 shell 命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);

	// 启用“DDE 执行”
	EnableShellOpen();
	RegisterShellFileTypes(TRUE);

	// 默认不新建文档
	cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;

	// 调度在命令行中指定的命令。如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序，则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;
	// 主窗口已初始化，因此显示它并对其进行更新
	pMainFrame->ShowWindow(m_nCmdShow);
	pMainFrame->UpdateWindow();

	return TRUE;
}

int CLogCCApp::ExitInstance() {
	//TODO: 处理可能已添加的附加资源
	LogPainterFactory::Release();
	ModelFactory::Release();

	AfxOleTerm(FALSE);

	return CWinAppEx::ExitInstance();
}

// CLogCCApp 消息处理程序

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx {
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL OnInitDialog();
private:
	CStatic versionDesc;
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) {
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX) {
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_VERSION_DESC, versionDesc);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// 用于运行对话框的应用程序命令
void CLogCCApp::OnAppAbout() {
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}

// CLogCCApp 自定义加载/保存方法

void CLogCCApp::PreLoadState() {
	BOOL bNameValid;
	CString strName;
	bNameValid = strName.LoadString(IDS_EDIT_MENU);
	ASSERT(bNameValid);
	GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EDIT);
}

void CLogCCApp::LoadCustomState() {
}

void CLogCCApp::SaveCustomState() {
}

// CLogCCApp 消息处理程序

BOOL CAboutDlg::OnInitDialog() {
	CDialogEx::OnInitDialog();

	TCHAR exePath[MAX_PATH];
	::GetModuleFileName(::AfxGetInstanceHandle(), exePath, MAX_PATH);

	CModuleVersion versionReader;
	versionReader.GetFileVersionInfo(exePath);

	basic_ostringstream<TCHAR> oss;
	oss << _T("LogCC ")
	    << HIWORD(versionReader.dwProductVersionMS) << _T(".")
	    << LOWORD(versionReader.dwProductVersionMS) << _T(".")
	    << HIWORD(versionReader.dwProductVersionLS) << _T(".")
	    << LOWORD(versionReader.dwProductVersionLS)
	    << _T("");
	versionDesc.SetWindowText(oss.str().c_str());

	oss.str(_T(""));

	return TRUE;  // return TRUE unless you set the focus to a control
	// 异常: OCX 属性页应返回 FALSE
}
<|endoftext|>