<commit_before>#pragma once

#include <iosfwd>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"
#include "sdd/order/order.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace hom {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief local homomorphism.
template <typename C>
struct LIBSDD_ATTRIBUTE_PACKED _local
{
  /// @brief The target of this homomorphism.
  const order_position_type target;

  /// @brief The nested homomorphism to apply in a nested level.
  const homomorphism<C> h;

  /// @brief Constructor.
  _local(order_position_type t, const homomorphism<C>& hm)
    : target(t), h(hm)
  {}

  /// @internal
  /// @brief Local's evaluation implementation.
  struct evaluation
  {
    /// @brief Used by variant.
    using result_type = SDD<C>;

    context<C>& cxt_;
    const order<C>& order_;
    const homomorphism<C> h_;

    evaluation(context<C>& cxt, const order<C>& o, const homomorphism<C>& h)
      : cxt_(cxt), order_(o), h_(h)
    {}

    /// @brief Hierarchical nodes case.
    SDD<C>
    operator()(const hierarchical_node<C>& node)
    const
    {
      if (h_.selector()) // partition won't change
      {
        dd::square_union<C, SDD<C>> su(cxt_.sdd_context());
        su.reserve(node.size());
        for (const auto& arc : node)
        {
          const SDD<C> new_valuation = h_(cxt_, order_.nested(), arc.valuation());
          if (not new_valuation.empty())
          {
            su.add(arc.successor(), new_valuation);
          }
        }
        return {node.variable(), su()};
      }
      else // partition will change
      {
        dd::sum_builder<C, SDD<C>> sum_operands(cxt_.sdd_context());
        sum_operands.reserve(node.size());
        for (const auto& arc : node)
        {
          const SDD<C> new_valuation = h_(cxt_, order_.nested(), arc.valuation());
          sum_operands.add(SDD<C>(node.variable(), new_valuation, arc.successor()));
        }
        return dd::sum(cxt_.sdd_context(), std::move(sum_operands));
      }
    }

    /// @brief Error case: local only applies on hierarchical nodes.
    template <typename T>
    SDD<C>
    operator()(const T&)
    const
    {
      assert(false && "Local applied on a flat node");
      __builtin_unreachable();
    }
  };

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const order<C>& o, const SDD<C>& s)
  const
  {
    return visit(evaluation{cxt, o, h}, s);
  }

  /// @brief Skip predicate.
  bool
  skip(const order<C>& o)
  const noexcept
  {
    return o.position() != target;
  }

  /// @brief Selector predicate
  bool
  selector()
  const noexcept
  {
    return h.selector();
  }

  friend
  bool
  operator==(const _local& lhs, const _local& rhs)
  noexcept
  {
    return lhs.target == rhs.target and lhs.h == rhs.h;
  }

  friend
  std::ostream&
  operator<<(std::ostream& os, const _local& l)
  {
    return os << "@(" << l.target << ", " << l.h << ")";
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace hom

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @related homomorphism
template <typename C>
homomorphism<C>
local(order_position_type pos, const homomorphism<C>& h)
{
  if (h == id<C>())
  {
    return h;
  }
  else
  {
    return homomorphism<C>::create(mem::construct<hom::_local<C>>(), pos, h);
  }
}

/// @brief Create the local homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
local(const typename C::Identifier& id, const order<C>& o, const homomorphism<C>& h)
{
  /// @todo Check that id is a hierarchical identifier.
  return local(o.node(id).position(), h);
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Hash specialization for sdd::hom::_local.
template <typename C>
struct hash<sdd::hom::_local<C>>
{
  std::size_t
  operator()(const sdd::hom::_local<C>& l)
  const
  {
    std::size_t seed = sdd::util::hash(l.target);
    sdd::util::hash_combine(seed, l.h);
    return seed;
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std
<commit_msg>Remove shadow warning with clang<commit_after>#pragma once

#include <iosfwd>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"
#include "sdd/order/order.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace hom {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief local homomorphism.
template <typename C>
struct LIBSDD_ATTRIBUTE_PACKED _local
{
  /// @brief The target of this homomorphism.
  const order_position_type target;

  /// @brief The nested homomorphism to apply in a nested level.
  const homomorphism<C> h;

  /// @brief Constructor.
  _local(order_position_type t, const homomorphism<C>& hm)
    : target(t), h(hm)
  {}

  /// @internal
  /// @brief Local's evaluation implementation.
  struct evaluation
  {
    /// @brief Used by variant.
    using result_type = SDD<C>;

    context<C>& cxt_;
    const order<C>& order_;
    const homomorphism<C> h_;

    evaluation(context<C>& cxt, const order<C>& o, const homomorphism<C>& op)
      : cxt_(cxt), order_(o), h_(op)
    {}

    /// @brief Hierarchical nodes case.
    SDD<C>
    operator()(const hierarchical_node<C>& node)
    const
    {
      if (h_.selector()) // partition won't change
      {
        dd::square_union<C, SDD<C>> su(cxt_.sdd_context());
        su.reserve(node.size());
        for (const auto& arc : node)
        {
          const SDD<C> new_valuation = h_(cxt_, order_.nested(), arc.valuation());
          if (not new_valuation.empty())
          {
            su.add(arc.successor(), new_valuation);
          }
        }
        return {node.variable(), su()};
      }
      else // partition will change
      {
        dd::sum_builder<C, SDD<C>> sum_operands(cxt_.sdd_context());
        sum_operands.reserve(node.size());
        for (const auto& arc : node)
        {
          const SDD<C> new_valuation = h_(cxt_, order_.nested(), arc.valuation());
          sum_operands.add(SDD<C>(node.variable(), new_valuation, arc.successor()));
        }
        return dd::sum(cxt_.sdd_context(), std::move(sum_operands));
      }
    }

    /// @brief Error case: local only applies on hierarchical nodes.
    template <typename T>
    SDD<C>
    operator()(const T&)
    const
    {
      assert(false && "Local applied on a flat node");
      __builtin_unreachable();
    }
  };

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const order<C>& o, const SDD<C>& s)
  const
  {
    return visit(evaluation{cxt, o, h}, s);
  }

  /// @brief Skip predicate.
  bool
  skip(const order<C>& o)
  const noexcept
  {
    return o.position() != target;
  }

  /// @brief Selector predicate
  bool
  selector()
  const noexcept
  {
    return h.selector();
  }

  friend
  bool
  operator==(const _local& lhs, const _local& rhs)
  noexcept
  {
    return lhs.target == rhs.target and lhs.h == rhs.h;
  }

  friend
  std::ostream&
  operator<<(std::ostream& os, const _local& l)
  {
    return os << "@(" << l.target << ", " << l.h << ")";
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace hom

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @related homomorphism
template <typename C>
homomorphism<C>
local(order_position_type pos, const homomorphism<C>& h)
{
  if (h == id<C>())
  {
    return h;
  }
  else
  {
    return homomorphism<C>::create(mem::construct<hom::_local<C>>(), pos, h);
  }
}

/// @brief Create the local homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
local(const typename C::Identifier& id, const order<C>& o, const homomorphism<C>& h)
{
  /// @todo Check that id is a hierarchical identifier.
  return local(o.node(id).position(), h);
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Hash specialization for sdd::hom::_local.
template <typename C>
struct hash<sdd::hom::_local<C>>
{
  std::size_t
  operator()(const sdd::hom::_local<C>& l)
  const
  {
    std::size_t seed = sdd::util::hash(l.target);
    sdd::util::hash_combine(seed, l.h);
    return seed;
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std
<|endoftext|>


<commit_before>// RUN: %clangxx -fsanitize=integer %s -o %t
// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOTYPE
// RUN: %env_ubsan_opts=report_error_type=1 %t 2>&1 | FileCheck %s --check-prefix=CHECK-TYPE
// REQUIRES: ubsan-asan

#include <stdint.h>

int main() {
  (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
  // CHECK-NOTYPE: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:44
  // CHECK-TYPE: SUMMARY: AddressSanitizer: unsigned-integer-overflow {{.*}}summary.cpp:[[@LINE-2]]:44
  return 0;
}
<commit_msg>[ubsan] Invoke test program using %run.<commit_after>// RUN: %clangxx -fsanitize=integer %s -o %t
// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOTYPE
// RUN: %env_ubsan_opts=report_error_type=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TYPE
// REQUIRES: ubsan-asan

#include <stdint.h>

int main() {
  (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
  // CHECK-NOTYPE: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:44
  // CHECK-TYPE: SUMMARY: AddressSanitizer: unsigned-integer-overflow {{.*}}summary.cpp:[[@LINE-2]]:44
  return 0;
}
<|endoftext|>


<commit_before>#include <QuantPDE/Core>
#include <QuantPDE/Modules/Payoffs>

// TODO: Change these includes; shouldn't include src directory explicitly
#include <QuantPDE/src/Modules/BlackScholes.hpp>

using namespace QuantPDE;
using namespace QuantPDE::Modules;

///////////////////////////////////////////////////////////////////////////////

#include <iostream>  // cout, cerr

using namespace std;

///////////////////////////////////////////////////////////////////////////////

int main() {

	const Real
		K = 100.,
		T = 1.,
		r_l = .03,
		r_b = .05,
		vol = .3
	;

	const unsigned
		N = 100
	;

	// Initial discretization
	RectilinearGrid1 grid(
		Axis {
			0., 10., 20., 30., 40., 50., 60., 70.,
			75., 80.,
			84., 88., 92.,
			94., 96., 98., 100., 102., 104., 106., 108., 110.,
			114., 118.,
			123.,
			130., 140., 150.,
			175.,
			225.,
			300.,
			750.,
			2000.,
			10000.
		}
	);

	// Control can be two interest rates: lending or borrowing
	RectilinearGrid1 controls( Axis { r_l, r_b } );

	// Payoff is a straddle
	auto payoff = QUANT_PDE_MODULES_PAYOFFS_STRADDLE_FIXED_STRIKE( K );

	// Iteration tree
	ReverseConstantStepper stepper(
		0.,
		T,  // Expiry time
		N   // Number of steps
	);
	ToleranceIteration tolerance;
	stepper.setInnerIteration(tolerance);

	// Linear system tree
	BlackScholes bs(
		grid,

		// Interest rate (passed as a control)
		Control1::make(grid),

		vol, // Volatility
		0.   // Dividend rate
	);
	MaxPolicyIteration1_1 policy(grid, controls, bs);
	policy.setIteration(tolerance);
	ReverseLinearBDFT bdf2(grid, policy);
	bdf2.setIteration(stepper);

	// Initial solution
	Vector initial = (PointwiseMap1(grid))(payoff);

	// Linear system solver
	BiCGSTABSolver solver;

	// Get solution
	Vector solutionVector = stepper.iterateUntilDone(
		initial,
		bdf2,
		solver
	);

	// Print solution
	cout << grid.accessor(solutionVector);

	return 0;

}

<commit_msg>Fixed typo.<commit_after>#include <QuantPDE/Core>
#include <QuantPDE/Modules/Payoffs>

// TODO: Change these includes; shouldn't include src directory explicitly
#include <QuantPDE/src/Modules/BlackScholes.hpp>

using namespace QuantPDE;
using namespace QuantPDE::Modules;

///////////////////////////////////////////////////////////////////////////////

#include <iostream>  // cout, cerr

using namespace std;

///////////////////////////////////////////////////////////////////////////////

int main() {

	const Real
		K = 100.,
		T = 1.,
		r_l = .03,
		r_b = .05,
		vol = .3
	;

	const unsigned
		N = 100
	;

	// Initial discretization
	RectilinearGrid1 grid(
		Axis {
			0., 10., 20., 30., 40., 50., 60., 70.,
			75., 80.,
			84., 88., 92.,
			94., 96., 98., 100., 102., 104., 106., 108., 110.,
			114., 118.,
			123.,
			130., 140., 150.,
			175.,
			225.,
			300.,
			750.,
			2000.,
			10000.
		}
	);

	// Control can be two interest rates: lending or borrowing
	RectilinearGrid1 controls( Axis { r_l, r_b } );

	// Payoff is a straddle
	auto payoff = QUANT_PDE_MODULES_PAYOFFS_STRADDLE_FIXED_STRIKE( K );

	// Iteration tree
	ReverseConstantStepper stepper(
		0.,
		T,  // Expiry time
		N   // Number of steps
	);
	ToleranceIteration tolerance;
	stepper.setInnerIteration(tolerance);

	// Linear system tree
	BlackScholes bs(
		grid,

		// Interest rate (passed as a control)
		Control1::make(grid),

		vol, // Volatility
		0.   // Dividend rate
	);
	MaxPolicyIteration1_1 policy(grid, controls, bs);
	policy.setIteration(tolerance);
	ReverseLinearBDFTwo bdf2(grid, policy);
	bdf2.setIteration(stepper);

	// Initial solution
	Vector initial = (PointwiseMap1(grid))(payoff);

	// Linear system solver
	BiCGSTABSolver solver;

	// Get solution
	Vector solutionVector = stepper.iterateUntilDone(
		initial,
		bdf2,
		solver
	);

	// Print solution
	cout << grid.accessor(solutionVector);

	return 0;

}

<|endoftext|>


<commit_before>/**
 * @file   LuaMachineTest.cpp
 * @brief  LuaMachine class tester.
 * @author zer0
 * @date   2019-04-27
 */

#include <gtest/gtest.h>
#include <libtbag/script/LuaMachine.hpp>
#include <libtbag/util/Version.hpp>

using namespace libtbag;
using namespace libtbag::script;
using namespace libtbag::util;

TEST(LuaMachineTest, Default)
{
    LuaMachine lua;
    lua.initDefault();
    ASSERT_EQ(0, lua._gettop());
    ASSERT_EQ(getTbagVersion().toString(), lua.getTbagVersion());
    ASSERT_EQ(0, lua._gettop());
}

<commit_msg>Create LuaMachineTest.StringLua_format tester.<commit_after>/**
 * @file   LuaMachineTest.cpp
 * @brief  LuaMachine class tester.
 * @author zer0
 * @date   2019-04-27
 */

#include <gtest/gtest.h>
#include <libtbag/script/LuaMachine.hpp>
#include <libtbag/util/Version.hpp>
#include <libtbag/log/Log.hpp>

using namespace libtbag;
using namespace libtbag::script;
using namespace libtbag::util;

TEST(LuaMachineTest, Default)
{
    libtbag::log::SeverityGuard guard;
    LuaMachine lua;
    lua.initDefault();
    ASSERT_EQ(0, lua._gettop());
    ASSERT_EQ(getTbagVersion().toString(), lua.getTbagVersion());
    ASSERT_EQ(0, lua._gettop());
}

TEST(LuaMachineTest, StringLua_format)
{
    libtbag::log::SeverityGuard guard;
    LuaMachine lua;
    lua.initDefault();
    char const * const TEST_SCRIPT = "text = tbag.format('Format: {}, {}, {}, {}', 'haha', 100, 1.9, true)";
    char const * const RESULT_TEXT = "Format: haha, 100, 1.9, true";
    ASSERT_TRUE(lua.runScript(TEST_SCRIPT));

    lua._getglobal("text");
    ASSERT_STREQ(RESULT_TEXT, lua._tostring(-1));
    lua._pop(1);
}

<|endoftext|>


<commit_before>
#pragma once

#include "testing_utilities/almost_equals.hpp"

#include <float.h>
#include <math.h>
#include <stdint.h>

#include <algorithm>
#include <string>

#include "geometry/grassmann.hpp"
#include "geometry/r3_element.hpp"
#include "gmock/gmock.h"
#include "numerics/ulp_distance.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {
namespace testing_utilities {
namespace internal_almost_equals {

using numerics::ULPDistance;

template<typename T>
testing::PolymorphicMatcher<AlmostEqualsMatcher<T>> AlmostEquals(
    T const& expected,
    std::int64_t const max_ulps) {
  return testing::MakePolymorphicMatcher(
      AlmostEqualsMatcher<T>(expected, max_ulps, max_ulps));
}

template<typename T>
testing::PolymorphicMatcher<AlmostEqualsMatcher<T>> AlmostEquals(
    T const& expected,
    std::int64_t const min_ulps,
    std::int64_t const max_ulps) {
  CHECK_LE(min_ulps, max_ulps);
  return testing::MakePolymorphicMatcher(
      AlmostEqualsMatcher<T>(expected, min_ulps, max_ulps));
}

template<typename T>
AlmostEqualsMatcher<T>::AlmostEqualsMatcher(T const& expected,
                                            std::int64_t const min_ulps,
                                            std::int64_t const max_ulps)
    : expected_(expected),
      min_ulps_(min_ulps),
      max_ulps_(max_ulps) {}

template<typename T>
template<typename Dimensions>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    quantities::Quantity<Dimensions> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const distance = ULPDistance(DoubleValue(actual),
                                            DoubleValue(expected_));
  bool const match =  min_ulps_ <= distance && distance <= max_ulps_;
  if (!match) {
    *listener << "the numbers are separated by " << distance << " ULPs";
  }
  return match;
}

template<typename T>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    double const actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const distance = ULPDistance(actual, expected_);
  bool const match =  min_ulps_ <= distance && distance <= max_ulps_;
  if (!match) {
    *listener << "the numbers are separated by " << distance << " ULPs";
  }
  return match;
}

template<typename T>
template<typename Scalar>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::R3Element<Scalar> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const x_distance = ULPDistance(DoubleValue(actual.x),
                                              DoubleValue(expected_.x));
  std::int64_t const y_distance = ULPDistance(DoubleValue(actual.y),
                                              DoubleValue(expected_.y));
  std::int64_t const z_distance = ULPDistance(DoubleValue(actual.z),
                                              DoubleValue(expected_.z));
  std::int64_t const max_distance =
      std::max({x_distance, y_distance, z_distance});
  bool const x_is_max = x_distance == max_distance;
  bool const y_is_max = y_distance == max_distance;
  bool const z_is_max = z_distance == max_distance;
  bool const matches = min_ulps_ <= max_distance && max_distance <= max_ulps_;
  if (!matches) {
    *listener << "the following components are not within "
              << min_ulps_ << " to " << max_ulps_ << " ULPs: "
              << (x_is_max ? "x, " : "") << (y_is_max ? "y, " : "")
              << (z_is_max ? "z, " : "");
    *listener << "the components differ by the following numbers of ULPs: x: "
              << x_distance << ", y: " << y_distance << ", z: " << z_distance;
  }
  return matches;
}

template<typename T>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Quaternion const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const w_distance = ULPDistance(
      DoubleValue(actual.real_part()),
      DoubleValue(expected_.real_part()));
  std::int64_t const x_distance = ULPDistance(
      DoubleValue(actual.imaginary_part().x),
      DoubleValue(expected_.imaginary_part().x));
  std::int64_t const y_distance = ULPDistance(
      DoubleValue(actual.imaginary_part().y),
      DoubleValue(expected_.imaginary_part().y));
  std::int64_t const z_distance = ULPDistance(
      DoubleValue(actual.imaginary_part().z),
      DoubleValue(expected_.imaginary_part().z));
  bool const w_matches = w_distance <= max_ulps_;
  bool const x_matches = x_distance <= max_ulps_;
  bool const y_matches = y_distance <= max_ulps_;
  bool const z_matches = z_distance <= max_ulps_;
  bool const matches = w_matches && x_matches && y_matches && z_matches;
  if (!matches) {
    *listener << "the following components differ by more than " << max_ulps_
              << " ULPs: "
              << (w_matches ? "" : "w, ") << (x_matches ? "" : "x, ")
              << (y_matches ? "" : "y, ") << (z_matches ? "" : "z, ");
    *listener << "the components differ by the following numbers of ULPs: w: "
              << w_distance << ", x: " << x_distance
              << ", y: " << y_distance << ", z: " << z_distance;
  }
  return matches;
}

template<typename T>
template<typename Scalar, typename Frame>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Vector<Scalar, Frame> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  return AlmostEqualsMatcher<geometry::R3Element<Scalar>>(
      expected_.coordinates(),
      min_ulps_,
      max_ulps_).MatchAndExplain(actual.coordinates(), listener);
}

template<typename T>
template<typename Scalar, typename Frame>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Bivector<Scalar, Frame> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  return AlmostEqualsMatcher<geometry::R3Element<Scalar>>(
      expected_.coordinates(),
      min_ulps_,
      max_ulps_).MatchAndExplain(actual.coordinates(), listener);
}

template<typename T>
template<typename Scalar, typename Frame>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Trivector<Scalar, Frame> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  return AlmostEqualsMatcher<Scalar>(expected_.coordinates(),
                                     min_ulps_,
                                     max_ulps_).MatchAndExplain(
                                         actual.coordinates(),
                                         listener);
}

template<typename T>
template<typename Vector>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Point<Vector> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  geometry::Point<Vector> const origin;
  return AlmostEqualsMatcher<Vector>(expected_ - origin,
                                     min_ulps_,
                                     max_ulps_).MatchAndExplain(
                                         actual - origin,
                                         listener);
}

template<typename T>
void AlmostEqualsMatcher<T>::DescribeTo(std::ostream* out) const {
  *out << "is within "<< min_ulps_
       << " to " << max_ulps_ << " ULPs of " << expected_;
}

template<typename T>
void AlmostEqualsMatcher<T>::DescribeNegationTo(std::ostream* out) const {
  *out << "is not within " << min_ulps_
       << " to " << max_ulps_ << " ULPs of " << expected_;
}

template<typename T>
bool AlmostEqualsMatcher<T>::MatchAndExplainIdentical(
    testing::MatchResultListener* listener) const {
  if (min_ulps_ == 0) {
    return true;
  } else {
    *listener << "the numbers are identical";
    return false;
  }
}

}  // namespace internal_almost_equals
}  // namespace testing_utilities
}  // namespace principia
<commit_msg>normalize NaNs in AlmostEquals<commit_after>
#pragma once

#include "testing_utilities/almost_equals.hpp"

#include <float.h>
#include <math.h>
#include <stdint.h>

#include <algorithm>
#include <string>

#include "geometry/grassmann.hpp"
#include "geometry/r3_element.hpp"
#include "gmock/gmock.h"
#include "numerics/ulp_distance.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {
namespace testing_utilities {
namespace internal_almost_equals {

// Make sure that this matcher treats all NaNs as almost equal to 0 ULPs.
inline double NormalizeNaN(double const x) {
  return std::isnan(x) ? std::numeric_limits<double>::quiet_NaN() : x;
}

inline NormalizedNaNULPDistance(double const x, double const y) {
  return numerics::ULPDistance(NormalizeNaN(x), NormalizeNaN(y));
}

template<typename T>
testing::PolymorphicMatcher<AlmostEqualsMatcher<T>> AlmostEquals(
    T const& expected,
    std::int64_t const max_ulps) {
  return testing::MakePolymorphicMatcher(
      AlmostEqualsMatcher<T>(expected, max_ulps, max_ulps));
}

template<typename T>
testing::PolymorphicMatcher<AlmostEqualsMatcher<T>> AlmostEquals(
    T const& expected,
    std::int64_t const min_ulps,
    std::int64_t const max_ulps) {
  CHECK_LE(min_ulps, max_ulps);
  return testing::MakePolymorphicMatcher(
      AlmostEqualsMatcher<T>(expected, min_ulps, max_ulps));
}

template<typename T>
AlmostEqualsMatcher<T>::AlmostEqualsMatcher(T const& expected,
                                            std::int64_t const min_ulps,
                                            std::int64_t const max_ulps)
    : expected_(expected),
      min_ulps_(min_ulps),
      max_ulps_(max_ulps) {}

template<typename T>
template<typename Dimensions>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    quantities::Quantity<Dimensions> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const distance =
      NormalizedNaNULPDistance(DoubleValue(actual), DoubleValue(expected_));
  bool const match =  min_ulps_ <= distance && distance <= max_ulps_;
  if (!match) {
    *listener << "the numbers are separated by " << distance << " ULPs";
  }
  return match;
}

template<typename T>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    double const actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const distance = NormalizedNaNULPDistance(actual, expected_);
  bool const match =  min_ulps_ <= distance && distance <= max_ulps_;
  if (!match) {
    *listener << "the numbers are separated by " << distance << " ULPs";
  }
  return match;
}

template<typename T>
template<typename Scalar>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::R3Element<Scalar> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const x_distance =
      NormalizedNaNULPDistance(DoubleValue(actual.x), DoubleValue(expected_.x));
  std::int64_t const y_distance =
      NormalizedNaNULPDistance(DoubleValue(actual.y), DoubleValue(expected_.y));
  std::int64_t const z_distance =
      NormalizedNaNULPDistance(DoubleValue(actual.z), DoubleValue(expected_.z));
  std::int64_t const max_distance =
      std::max({x_distance, y_distance, z_distance});
  bool const x_is_max = x_distance == max_distance;
  bool const y_is_max = y_distance == max_distance;
  bool const z_is_max = z_distance == max_distance;
  bool const matches = min_ulps_ <= max_distance && max_distance <= max_ulps_;
  if (!matches) {
    *listener << "the following components are not within "
              << min_ulps_ << " to " << max_ulps_ << " ULPs: "
              << (x_is_max ? "x, " : "") << (y_is_max ? "y, " : "")
              << (z_is_max ? "z, " : "");
    *listener << "the components differ by the following numbers of ULPs: x: "
              << x_distance << ", y: " << y_distance << ", z: " << z_distance;
  }
  return matches;
}

template<typename T>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Quaternion const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  std::int64_t const w_distance = NormalizedNaNULPDistance(
      DoubleValue(actual.real_part()), DoubleValue(expected_.real_part()));
  std::int64_t const x_distance =
      NormalizedNaNULPDistance(DoubleValue(actual.imaginary_part().x),
                               DoubleValue(expected_.imaginary_part().x));
  std::int64_t const y_distance =
      NormalizedNaNULPDistance(DoubleValue(actual.imaginary_part().y),
                               DoubleValue(expected_.imaginary_part().y));
  std::int64_t const z_distance =
      NormalizedNaNULPDistance(DoubleValue(actual.imaginary_part().z),
                               DoubleValue(expected_.imaginary_part().z));
  bool const w_matches = w_distance <= max_ulps_;
  bool const x_matches = x_distance <= max_ulps_;
  bool const y_matches = y_distance <= max_ulps_;
  bool const z_matches = z_distance <= max_ulps_;
  bool const matches = w_matches && x_matches && y_matches && z_matches;
  if (!matches) {
    *listener << "the following components differ by more than " << max_ulps_
              << " ULPs: "
              << (w_matches ? "" : "w, ") << (x_matches ? "" : "x, ")
              << (y_matches ? "" : "y, ") << (z_matches ? "" : "z, ");
    *listener << "the components differ by the following numbers of ULPs: w: "
              << w_distance << ", x: " << x_distance
              << ", y: " << y_distance << ", z: " << z_distance;
  }
  return matches;
}

template<typename T>
template<typename Scalar, typename Frame>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Vector<Scalar, Frame> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  return AlmostEqualsMatcher<geometry::R3Element<Scalar>>(
      expected_.coordinates(),
      min_ulps_,
      max_ulps_).MatchAndExplain(actual.coordinates(), listener);
}

template<typename T>
template<typename Scalar, typename Frame>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Bivector<Scalar, Frame> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  return AlmostEqualsMatcher<geometry::R3Element<Scalar>>(
      expected_.coordinates(),
      min_ulps_,
      max_ulps_).MatchAndExplain(actual.coordinates(), listener);
}

template<typename T>
template<typename Scalar, typename Frame>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Trivector<Scalar, Frame> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  return AlmostEqualsMatcher<Scalar>(expected_.coordinates(),
                                     min_ulps_,
                                     max_ulps_).MatchAndExplain(
                                         actual.coordinates(),
                                         listener);
}

template<typename T>
template<typename Vector>
bool AlmostEqualsMatcher<T>::MatchAndExplain(
    geometry::Point<Vector> const& actual,
    testing::MatchResultListener* listener) const {
  // Check that the types are equality-comparable up to implicit casts.
  if (actual == expected_) {
    return MatchAndExplainIdentical(listener);
  }
  geometry::Point<Vector> const origin;
  return AlmostEqualsMatcher<Vector>(expected_ - origin,
                                     min_ulps_,
                                     max_ulps_).MatchAndExplain(
                                         actual - origin,
                                         listener);
}

template<typename T>
void AlmostEqualsMatcher<T>::DescribeTo(std::ostream* out) const {
  *out << "is within "<< min_ulps_
       << " to " << max_ulps_ << " ULPs of " << expected_;
}

template<typename T>
void AlmostEqualsMatcher<T>::DescribeNegationTo(std::ostream* out) const {
  *out << "is not within " << min_ulps_
       << " to " << max_ulps_ << " ULPs of " << expected_;
}

template<typename T>
bool AlmostEqualsMatcher<T>::MatchAndExplainIdentical(
    testing::MatchResultListener* listener) const {
  if (min_ulps_ == 0) {
    return true;
  } else {
    *listener << "the numbers are identical";
    return false;
  }
}

}  // namespace internal_almost_equals
}  // namespace testing_utilities
}  // namespace principia
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "BackendPasses.h"

#include "llvm/Analysis/InlineCost.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/Inliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Scalar.h"

//#include "clang/Basic/LangOptions.h"
//#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CodeGenOptions.h"

using namespace cling;
using namespace clang;
using namespace llvm;
using namespace llvm::legacy;

namespace {
  class KeepLocalGVPass: public ModulePass {
    static char ID;

    bool runOnGlobal(GlobalValue& GV) {
      if (GV.isDeclaration())
        return false; // no change.

      // GV is a definition.

      llvm::GlobalValue::LinkageTypes LT = GV.getLinkage();
      if (!GV.isDiscardableIfUnused(LT))
        return false;

      if (LT == llvm::GlobalValue::InternalLinkage
          || LT == llvm::GlobalValue::PrivateLinkage) {
        GV.setLinkage(llvm::GlobalValue::ExternalLinkage);
        return true; // a change!
      }
      return false;
    }

  public:
    KeepLocalGVPass() : ModulePass(ID) {}

    bool runOnModule(Module &M) override {
      bool ret = false;
      for (auto &&F: M)
        ret |= runOnGlobal(F);
      for (auto &&G: M.globals())
        ret |= runOnGlobal(G);
      return ret;
    }
  };
}

char KeepLocalGVPass::ID = 0;

BackendPasses::~BackendPasses() {
  //delete m_PMBuilder->Inliner;
}

void BackendPasses::CreatePasses(llvm::Module& M, int OptLevel)
{
  // From BackEndUtil's clang::EmitAssemblyHelper::CreatePasses().

#if 0
  CodeGenOptions::InliningMethod Inlining = m_CGOpts.getInlining();
  CodeGenOptions& CGOpts_ = const_cast<CodeGenOptions&>(m_CGOpts);
  // DON'T: we will not find our symbols...
  //CGOpts_.CXXCtorDtorAliases = 1;

  // Default clang -O2 on Linux 64bit also has the following, but see
  // CIFactory.cpp.
  CGOpts_.DisableFPElim = 0;
  CGOpts_.DiscardValueNames = 1;
  CGOpts_.OmitLeafFramePointer = 1;
  CGOpts_.OptimizationLevel = 2;
  CGOpts_.RelaxAll = 0;
  CGOpts_.UnrollLoops = 1;
  CGOpts_.VectorizeLoop = 1;
  CGOpts_.VectorizeSLP = 1;
#endif

#if 0 // def __GNUC__
  // Better inlining is pending https://bugs.llvm.org//show_bug.cgi?id=19668
  // and its consequence https://sft.its.cern.ch/jira/browse/ROOT-7111
  // shown e.g. by roottest/cling/stl/map/badstringMap
  if (Inlining > CodeGenOptions::NormalInlining)
    Inlining = CodeGenOptions::NormalInlining;
#endif

  // Handle disabling of LLVM optimization, where we want to preserve the
  // internal module before any optimization.
  if (m_CGOpts.DisableLLVMPasses) {
    OptLevel = 0;
    // Always keep at least ForceInline - NoInlining is deadly for libc++.
    // Inlining = CGOpts.NoInlining;
  }

  llvm::PassManagerBuilder PMBuilder;
  PMBuilder.OptLevel = OptLevel;
  PMBuilder.SizeLevel = m_CGOpts.OptimizeSize;
  PMBuilder.BBVectorize = 0; // m_CGOpts.VectorizeBB;
  PMBuilder.SLPVectorize = OptLevel > 1 ? 1 : 0; // m_CGOpts.VectorizeSLP
  PMBuilder.LoopVectorize = OptLevel > 1 ? 1 : 0; // m_CGOpts.VectorizeLoop

  PMBuilder.DisableTailCalls = m_CGOpts.DisableTailCalls;
  PMBuilder.DisableUnrollLoops = !m_CGOpts.UnrollLoops;
  PMBuilder.MergeFunctions = m_CGOpts.MergeFunctions;
  PMBuilder.RerollLoops = m_CGOpts.RerollLoops;

  PMBuilder.LibraryInfo = new TargetLibraryInfoImpl(m_TM.getTargetTriple());

  // At O0 and O1 we only run the always inliner which is more efficient. At
  // higher optimization levels we run the normal inliner.
  if (m_CGOpts.OptimizationLevel <= 1) {
    bool InsertLifetimeIntrinsics = m_CGOpts.OptimizationLevel != 0;
    PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
  } else {
    PMBuilder.Inliner = createFunctionInliningPass(m_CGOpts.OptimizationLevel,
                                                   m_CGOpts.OptimizeSize,
            (!m_CGOpts.SampleProfileFile.empty() && m_CGOpts.EmitSummaryIndex));
  }

  // Set up the per-module pass manager.
  m_MPM[OptLevel].reset(new legacy::PassManager());

  m_MPM[OptLevel]->add(new KeepLocalGVPass());
  m_MPM[OptLevel]->add(createTargetTransformInfoWrapperPass(
                                                   m_TM.getTargetIRAnalysis()));

  m_TM.adjustPassManager(PMBuilder);

  PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
                         [&](const PassManagerBuilder &,
                             legacy::PassManagerBase &PM) {
                              PM.add(createAddDiscriminatorsPass());
                            });

  //if (!CGOpts.RewriteMapFiles.empty())
  //  addSymbolRewriterPass(CGOpts, m_MPM);

  PMBuilder.populateModulePassManager(*m_MPM[OptLevel]);

  m_FPM[OptLevel].reset(new legacy::FunctionPassManager(&M));
  m_FPM[OptLevel]->add(createTargetTransformInfoWrapperPass(
                                                   m_TM.getTargetIRAnalysis()));
  if (m_CGOpts.VerifyModule)
      m_FPM[OptLevel]->add(createVerifierPass());
  PMBuilder.populateFunctionPassManager(*m_FPM[OptLevel]);
}

void BackendPasses::runOnModule(Module& M, int OptLevel) {

  if (OptLevel < 0)
    OptLevel = 0;
  if (OptLevel > 3)
    OptLevel = 3;

  if (!m_MPM[OptLevel])
    CreatePasses(M, OptLevel);

  static constexpr std::array<llvm::CodeGenOpt::Level, 4> CGOptLevel {{
    llvm::CodeGenOpt::None,
    llvm::CodeGenOpt::Less,
    llvm::CodeGenOpt::Default,
    llvm::CodeGenOpt::Aggressive
  }};
  // TM's OptLevel is used to build orc::SimpleCompiler passes for every Module.
  m_TM.setOptLevel(CGOptLevel[OptLevel]);

  // Run the per-function passes on the module.
  m_FPM[OptLevel]->doInitialization();
  for (auto&& I: M.functions())
    if (!I.isDeclaration())
      m_FPM[OptLevel]->run(I);
  m_FPM[OptLevel]->doFinalization();

  m_MPM[OptLevel]->run(M);
}
<commit_msg>BBVectorize flag was unused and went away in LLVM 5.0<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "BackendPasses.h"

#include "llvm/Analysis/InlineCost.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/Inliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Scalar.h"

//#include "clang/Basic/LangOptions.h"
//#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CodeGenOptions.h"

using namespace cling;
using namespace clang;
using namespace llvm;
using namespace llvm::legacy;

namespace {
  class KeepLocalGVPass: public ModulePass {
    static char ID;

    bool runOnGlobal(GlobalValue& GV) {
      if (GV.isDeclaration())
        return false; // no change.

      // GV is a definition.

      llvm::GlobalValue::LinkageTypes LT = GV.getLinkage();
      if (!GV.isDiscardableIfUnused(LT))
        return false;

      if (LT == llvm::GlobalValue::InternalLinkage
          || LT == llvm::GlobalValue::PrivateLinkage) {
        GV.setLinkage(llvm::GlobalValue::ExternalLinkage);
        return true; // a change!
      }
      return false;
    }

  public:
    KeepLocalGVPass() : ModulePass(ID) {}

    bool runOnModule(Module &M) override {
      bool ret = false;
      for (auto &&F: M)
        ret |= runOnGlobal(F);
      for (auto &&G: M.globals())
        ret |= runOnGlobal(G);
      return ret;
    }
  };
}

char KeepLocalGVPass::ID = 0;

BackendPasses::~BackendPasses() {
  //delete m_PMBuilder->Inliner;
}

void BackendPasses::CreatePasses(llvm::Module& M, int OptLevel)
{
  // From BackEndUtil's clang::EmitAssemblyHelper::CreatePasses().

#if 0
  CodeGenOptions::InliningMethod Inlining = m_CGOpts.getInlining();
  CodeGenOptions& CGOpts_ = const_cast<CodeGenOptions&>(m_CGOpts);
  // DON'T: we will not find our symbols...
  //CGOpts_.CXXCtorDtorAliases = 1;

  // Default clang -O2 on Linux 64bit also has the following, but see
  // CIFactory.cpp.
  CGOpts_.DisableFPElim = 0;
  CGOpts_.DiscardValueNames = 1;
  CGOpts_.OmitLeafFramePointer = 1;
  CGOpts_.OptimizationLevel = 2;
  CGOpts_.RelaxAll = 0;
  CGOpts_.UnrollLoops = 1;
  CGOpts_.VectorizeLoop = 1;
  CGOpts_.VectorizeSLP = 1;
#endif

#if 0 // def __GNUC__
  // Better inlining is pending https://bugs.llvm.org//show_bug.cgi?id=19668
  // and its consequence https://sft.its.cern.ch/jira/browse/ROOT-7111
  // shown e.g. by roottest/cling/stl/map/badstringMap
  if (Inlining > CodeGenOptions::NormalInlining)
    Inlining = CodeGenOptions::NormalInlining;
#endif

  // Handle disabling of LLVM optimization, where we want to preserve the
  // internal module before any optimization.
  if (m_CGOpts.DisableLLVMPasses) {
    OptLevel = 0;
    // Always keep at least ForceInline - NoInlining is deadly for libc++.
    // Inlining = CGOpts.NoInlining;
  }

  llvm::PassManagerBuilder PMBuilder;
  PMBuilder.OptLevel = OptLevel;
  PMBuilder.SizeLevel = m_CGOpts.OptimizeSize;
  PMBuilder.SLPVectorize = OptLevel > 1 ? 1 : 0; // m_CGOpts.VectorizeSLP
  PMBuilder.LoopVectorize = OptLevel > 1 ? 1 : 0; // m_CGOpts.VectorizeLoop

  PMBuilder.DisableTailCalls = m_CGOpts.DisableTailCalls;
  PMBuilder.DisableUnrollLoops = !m_CGOpts.UnrollLoops;
  PMBuilder.MergeFunctions = m_CGOpts.MergeFunctions;
  PMBuilder.RerollLoops = m_CGOpts.RerollLoops;

  PMBuilder.LibraryInfo = new TargetLibraryInfoImpl(m_TM.getTargetTriple());

  // At O0 and O1 we only run the always inliner which is more efficient. At
  // higher optimization levels we run the normal inliner.
  if (m_CGOpts.OptimizationLevel <= 1) {
    bool InsertLifetimeIntrinsics = m_CGOpts.OptimizationLevel != 0;
    PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
  } else {
    PMBuilder.Inliner = createFunctionInliningPass(m_CGOpts.OptimizationLevel,
                                                   m_CGOpts.OptimizeSize,
            (!m_CGOpts.SampleProfileFile.empty() && m_CGOpts.EmitSummaryIndex));
  }

  // Set up the per-module pass manager.
  m_MPM[OptLevel].reset(new legacy::PassManager());

  m_MPM[OptLevel]->add(new KeepLocalGVPass());
  m_MPM[OptLevel]->add(createTargetTransformInfoWrapperPass(
                                                   m_TM.getTargetIRAnalysis()));

  m_TM.adjustPassManager(PMBuilder);

  PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
                         [&](const PassManagerBuilder &,
                             legacy::PassManagerBase &PM) {
                              PM.add(createAddDiscriminatorsPass());
                            });

  //if (!CGOpts.RewriteMapFiles.empty())
  //  addSymbolRewriterPass(CGOpts, m_MPM);

  PMBuilder.populateModulePassManager(*m_MPM[OptLevel]);

  m_FPM[OptLevel].reset(new legacy::FunctionPassManager(&M));
  m_FPM[OptLevel]->add(createTargetTransformInfoWrapperPass(
                                                   m_TM.getTargetIRAnalysis()));
  if (m_CGOpts.VerifyModule)
      m_FPM[OptLevel]->add(createVerifierPass());
  PMBuilder.populateFunctionPassManager(*m_FPM[OptLevel]);
}

void BackendPasses::runOnModule(Module& M, int OptLevel) {

  if (OptLevel < 0)
    OptLevel = 0;
  if (OptLevel > 3)
    OptLevel = 3;

  if (!m_MPM[OptLevel])
    CreatePasses(M, OptLevel);

  static constexpr std::array<llvm::CodeGenOpt::Level, 4> CGOptLevel {{
    llvm::CodeGenOpt::None,
    llvm::CodeGenOpt::Less,
    llvm::CodeGenOpt::Default,
    llvm::CodeGenOpt::Aggressive
  }};
  // TM's OptLevel is used to build orc::SimpleCompiler passes for every Module.
  m_TM.setOptLevel(CGOptLevel[OptLevel]);

  // Run the per-function passes on the module.
  m_FPM[OptLevel]->doInitialization();
  for (auto&& I: M.functions())
    if (!I.isDeclaration())
      m_FPM[OptLevel]->run(I);
  m_FPM[OptLevel]->doFinalization();

  m_MPM[OptLevel]->run(M);
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2020 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Wilfried Goesgens
////////////////////////////////////////////////////////////////////////////////

#include "AqlUserFunctions.h"

#include "Aql/Query.h"
#include "Aql/QueryRegistry.h"
#include "Aql/QueryString.h"
#include "Basics/StaticStrings.h"
#include "Basics/StringUtils.h"
#include "Basics/VelocyPackHelper.h"
#include "RestServer/QueryRegistryFeature.h"
#include "Transaction/Helpers.h"
#include "Transaction/Methods.h"
#include "Transaction/StandaloneContext.h"
#include "Transaction/V8Context.h"
#include "Utils/OperationOptions.h"
#include "Utils/SingleCollectionTransaction.h"
#include "V8/JavaScriptSecurityContext.h"
#include "V8/v8-globals.h"
#include "V8/v8-utils.h"
#include "V8Server/V8DealerFeature.h"

#include <v8.h>
#include <velocypack/Builder.h>
#include <velocypack/Iterator.h>
#include <velocypack/StringRef.h>
#include <velocypack/velocypack-aliases.h>
#include <regex>

using namespace arangodb;

namespace {
std::string const collectionName("_aqlfunctions");

// Must not start with `_`, may contain alphanumerical characters, should have
// at least one set of double colons followed by more alphanumerical characters.
std::regex const funcRegEx("[a-zA-Z0-9][a-zA-Z0-9_]*(::[a-zA-Z0-9_]+)+", std::regex::ECMAScript);

// we may filter less restrictive:
std::regex const funcFilterRegEx("[a-zA-Z0-9_]+(::[a-zA-Z0-9_]*)*", std::regex::ECMAScript);

bool isValidFunctionName(std::string const& testName) {
  return std::regex_match(testName, funcRegEx);
}

bool isValidFunctionNameFilter(std::string const& testName) {
  return std::regex_match(testName, funcFilterRegEx);
}

void reloadAqlUserFunctions() {
  std::string const def("reloadAql");
  V8DealerFeature::DEALER->addGlobalContextMethod(def);
}

}  // namespace

Result arangodb::unregisterUserFunction(TRI_vocbase_t& vocbase, std::string const& functionName) {
  if (functionName.empty() || !isValidFunctionNameFilter(functionName)) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  std::string("error deleting AQL user function: '") +
                      functionName + "' contains invalid characters");
  }

  std::string aql(
      "FOR fn IN @@col FILTER fn._key == @fnName REMOVE { _key: fn._key } in "
      "@@col RETURN 1");
  std::string UCFN = basics::StringUtils::toupper(functionName);

  auto binds = std::make_shared<VPackBuilder>();
  binds->openObject();
  binds->add("fnName", VPackValue(UCFN));
  binds->add("@col", VPackValue(collectionName));
  binds->close();  // obj

  {
    arangodb::aql::Query query(transaction::V8Context::CreateWhenRequired(vocbase, true),
                               arangodb::aql::QueryString(aql), binds, nullptr);
    aql::QueryResult queryResult = query.executeSync();

    if (queryResult.result.fail()) {
      if (queryResult.result.is(TRI_ERROR_REQUEST_CANCELED) ||
          (queryResult.result.is(TRI_ERROR_QUERY_KILLED))) {
        return Result(TRI_ERROR_REQUEST_CANCELED);
      }
      return queryResult.result;
    }

    VPackSlice countSlice = queryResult.data->slice();
    if (!countSlice.isArray()) {
      return Result(TRI_ERROR_INTERNAL,
                    "bad query result for deleting AQL user functions");
    }

    if (countSlice.length() != 1) {
      return Result(TRI_ERROR_QUERY_FUNCTION_NOT_FOUND,
                    std::string("no AQL user function with name '") +
                        functionName + "' found");
    }
  }

  reloadAqlUserFunctions();
  return Result();
}

Result arangodb::unregisterUserFunctionsGroup(TRI_vocbase_t& vocbase,
                                              std::string const& functionFilterPrefix,
                                              int& deleteCount) {
  deleteCount = 0;

  if (functionFilterPrefix.empty()) {
    return Result(TRI_ERROR_BAD_PARAMETER);
  }

  if (!isValidFunctionNameFilter(functionFilterPrefix)) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  std::string("error deleting AQL user function: '") +
                      functionFilterPrefix + "' contains invalid characters");
  }

  std::string uc(functionFilterPrefix);
  basics::StringUtils::toupperInPlace(uc);

  if ((uc.length() < 2) || (uc[uc.length() - 1] != ':') || (uc[uc.length() - 2] != ':')) {
    uc += "::";
  }

  auto binds = std::make_shared<VPackBuilder>();
  binds->openObject();
  binds->add("fnLength", VPackValue(uc.length()));
  binds->add("ucName", VPackValue(uc));
  binds->add("@col", VPackValue(collectionName));
  binds->close();

  std::string aql(
      "FOR fn IN @@col FILTER UPPER(LEFT(fn.name, @fnLength)) == @ucName "
      "REMOVE { _key: fn._key} in @@col RETURN 1");

  {
    arangodb::aql::Query query(transaction::V8Context::CreateWhenRequired(vocbase, true),
                               arangodb::aql::QueryString(aql), binds, nullptr);
    aql::QueryResult queryResult = query.executeSync();

    if (queryResult.result.fail()) {
      if (queryResult.result.is(TRI_ERROR_REQUEST_CANCELED) ||
          (queryResult.result.is(TRI_ERROR_QUERY_KILLED))) {
        return Result(TRI_ERROR_REQUEST_CANCELED);
      }
      return queryResult.result;
    }

    VPackSlice countSlice = queryResult.data->slice();
    if (!countSlice.isArray()) {
      return Result(TRI_ERROR_INTERNAL,
                    "bad query result for deleting AQL user functions");
    }

    deleteCount = static_cast<int>(countSlice.length());
  }

  reloadAqlUserFunctions();
  return Result();
}

Result arangodb::registerUserFunction(TRI_vocbase_t& vocbase, velocypack::Slice userFunction,
                                      bool& replacedExisting) {
  replacedExisting = false;

  Result res;
  std::string name;

  try {
    auto vname = userFunction.get("name");
    if (!vname.isString()) {
      return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                    "function name has to be provided as a string");
    }
    name = vname.copyString();
    if (name.empty()) {
      return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                    "function name has to be provided and must not be empty");
    }
  } catch (...) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  "missing mandatory attribute 'name'");
  }

  if (!isValidFunctionName(name)) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  std::string("error creating AQL user function: '") + name +
                      "' is not a valid name");
  }

  auto cvString = userFunction.get("code");
  if (!cvString.isString() || cvString.getStringLength() == 0) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE,
                  "expecting string with function definition");
  }

  std::string tmp = cvString.copyString();
  std::string code = std::string("(") + tmp + "\n)";

  bool isDeterministic = false;
  VPackSlice isDeterministicSlice = userFunction.get("isDeterministic");
  if (isDeterministicSlice.isBoolean()) {
    isDeterministic = isDeterministicSlice.getBoolean();
  }

  {
    ISOLATE;
    bool throwV8Exception = (isolate != nullptr);

    JavaScriptSecurityContext securityContext = JavaScriptSecurityContext::createRestrictedContext();
    V8ConditionalContextGuard contextGuard(res, isolate, &vocbase, securityContext);

    if (res.fail()) {
      return res;
    }

    std::string testCode("(function() { var callback = ");
    testCode += tmp + "; return callback; })()";
    v8::HandleScope scope(isolate);

    v8::Handle<v8::Value> result;
    {
      v8::TryCatch tryCatch(isolate);

      result = TRI_ExecuteJavaScriptString(isolate, isolate->GetCurrentContext(),
                                           TRI_V8_STD_STRING(isolate, testCode),
                                           TRI_V8_ASCII_STRING(isolate,
                                                               "userFunction"),
                                           false);

      if (result.IsEmpty() || !result->IsFunction() || tryCatch.HasCaught()) {
        if (tryCatch.HasCaught()) {
          res.reset(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE,
                    std::string(TRI_errno_string(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE)) +
                        ": " + TRI_StringifyV8Exception(isolate, &tryCatch));

          if (!tryCatch.CanContinue()) {
            if (throwV8Exception) {
              tryCatch.ReThrow();
            }
            TRI_GET_GLOBALS();
            v8g->_canceled = true;
          }
        } else {
          res.reset(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE,
                    std::string(TRI_errno_string(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE)));
        }
      }
    }
  }
  if (!res.ok()) {
    return res;
  }
  std::string _key(name);
  basics::StringUtils::toupperInPlace(_key);

  VPackBuilder oneFunctionDocument;
  oneFunctionDocument.openObject();
  oneFunctionDocument.add(StaticStrings::KeyString, VPackValue(_key));
  oneFunctionDocument.add("name", VPackValue(name));
  oneFunctionDocument.add("code", VPackValue(code));
  oneFunctionDocument.add("isDeterministic", VPackValue(isDeterministic));
  oneFunctionDocument.close();

  {
    arangodb::OperationOptions opOptions;
    opOptions.waitForSync = true;
    opOptions.returnOld = true;
    opOptions.overwriteMode = OperationOptions::OverwriteMode::Replace;

    // find and load collection given by name or identifier
    auto ctx = transaction::V8Context::CreateWhenRequired(vocbase, true);
    SingleCollectionTransaction trx(ctx, collectionName, AccessMode::Type::WRITE);

    res = trx.begin();
    if (res.fail()) {
      return res;
    }

    arangodb::OperationResult result =
        trx.insert(collectionName, oneFunctionDocument.slice(), opOptions);

    if (result.ok()) {
      VPackSlice oldSlice = result.slice().get(StaticStrings::Old);
      replacedExisting = !(oldSlice.isNone() || oldSlice.isNull());
    }
    // Will commit if no error occured.
    // or abort if an error occured.
    // result stays valid!
    res = trx.finish(result.result);
  }

  if (res.ok()) {
    reloadAqlUserFunctions();
  }

  return res;
}

Result arangodb::toArrayUserFunctions(TRI_vocbase_t& vocbase,
                                      std::string const& functionFilterPrefix,
                                      velocypack::Builder& result) {
  std::string aql;
  auto binds = std::make_shared<VPackBuilder>();

  binds->openObject();

  if (!functionFilterPrefix.empty()) {
    aql =
        "FOR function IN @@col FILTER LEFT(function._key, @fnLength) == "
        "@ucName RETURN function";

    std::string uc(functionFilterPrefix);
    basics::StringUtils::toupperInPlace(uc);

    if ((uc.length() < 2) || (uc[uc.length() - 1] != ':') || (uc[uc.length() - 2] != ':')) {
      uc += "::";
    }

    binds->add("fnLength", VPackValue(uc.length()));
    binds->add("ucName", VPackValue(uc));
  } else {
    aql = "FOR function IN @@col RETURN function";
  }

  binds->add("@col", VPackValue(collectionName));
  binds->close();

  arangodb::aql::Query query(transaction::V8Context::CreateWhenRequired(vocbase, true),
                             arangodb::aql::QueryString(aql), binds, nullptr);
  aql::QueryResult queryResult = query.executeSync();

  if (queryResult.result.fail()) {
    if (queryResult.result.is(TRI_ERROR_REQUEST_CANCELED) ||
        (queryResult.result.is(TRI_ERROR_QUERY_KILLED))) {
      return Result(TRI_ERROR_REQUEST_CANCELED);
    }
    return queryResult.result;
  }

  auto usersFunctionsSlice = queryResult.data->slice();

  if (!usersFunctionsSlice.isArray()) {
    return Result(TRI_ERROR_INTERNAL,
                  "bad query result for AQL user functions");
  }

  result.openArray();
  std::string tmp;
  for (VPackSlice it : VPackArrayIterator(usersFunctionsSlice)) {
    VPackSlice resolved;
    resolved = it.resolveExternal();

    if (!resolved.isObject()) {
      return Result(TRI_ERROR_INTERNAL,
                    "element that stores AQL user function is not an object");
    }

    VPackSlice name, fn, dtm;
    bool isDeterministic = false;
    name = resolved.get("name");
    fn = resolved.get("code");
    dtm = resolved.get("isDeterministic");
    if (dtm.isBoolean()) {
      isDeterministic = dtm.getBool();
    }
    // We simply ignore invalid entries in the _functions collection:
    if (name.isString() && fn.isString() && (fn.getStringLength() > 2)) {
      auto ref = arangodb::velocypack::StringRef(fn);

      ref = ref.substr(1, ref.length() - 2);
      tmp = basics::StringUtils::trim(ref.toString());

      VPackBuilder oneFunction;
      oneFunction.openObject();
      oneFunction.add("name", name);
      oneFunction.add("code", VPackValue(tmp));
      oneFunction.add("isDeterministic", VPackValue(isDeterministic));
      oneFunction.close();
      result.add(oneFunction.slice());
    }
  }
  result.close();  // close Array

  return Result();
}
<commit_msg>don't run a full-fledged AQL query to remove an AQL UDF by key (#12699)<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2020 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Wilfried Goesgens
////////////////////////////////////////////////////////////////////////////////

#include "AqlUserFunctions.h"

#include "Aql/Query.h"
#include "Aql/QueryRegistry.h"
#include "Aql/QueryString.h"
#include "Basics/StaticStrings.h"
#include "Basics/StringUtils.h"
#include "Basics/VelocyPackHelper.h"
#include "RestServer/QueryRegistryFeature.h"
#include "Transaction/Helpers.h"
#include "Transaction/Methods.h"
#include "Transaction/StandaloneContext.h"
#include "Transaction/V8Context.h"
#include "Utils/OperationOptions.h"
#include "Utils/SingleCollectionTransaction.h"
#include "V8/JavaScriptSecurityContext.h"
#include "V8/v8-globals.h"
#include "V8/v8-utils.h"
#include "V8Server/V8DealerFeature.h"

#include <v8.h>
#include <velocypack/Builder.h>
#include <velocypack/Iterator.h>
#include <velocypack/StringRef.h>
#include <velocypack/velocypack-aliases.h>
#include <regex>

using namespace arangodb;

namespace {
// Must not start with `_`, may contain alphanumerical characters, should have
// at least one set of double colons followed by more alphanumerical characters.
std::regex const funcRegEx("[a-zA-Z0-9][a-zA-Z0-9_]*(::[a-zA-Z0-9_]+)+", std::regex::ECMAScript);

// we may filter less restrictive:
std::regex const funcFilterRegEx("[a-zA-Z0-9_]+(::[a-zA-Z0-9_]*)*", std::regex::ECMAScript);

bool isValidFunctionName(std::string const& testName) {
  return std::regex_match(testName, funcRegEx);
}

bool isValidFunctionNameFilter(std::string const& testName) {
  return std::regex_match(testName, funcFilterRegEx);
}

void reloadAqlUserFunctions() {
  if (V8DealerFeature::DEALER && V8DealerFeature::DEALER->isEnabled()) {
    std::string const def("reloadAql");
    V8DealerFeature::DEALER->addGlobalContextMethod(def);
  }
}

}  // namespace

Result arangodb::unregisterUserFunction(TRI_vocbase_t& vocbase, std::string const& functionName) {
  if (functionName.empty() || !isValidFunctionNameFilter(functionName)) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  std::string("error deleting AQL user function: '") +
                      functionName + "' contains invalid characters");
  }

  std::string UCFN = basics::StringUtils::toupper(functionName);
  Result res;
  {
    VPackBuilder builder;
    {
      VPackObjectBuilder guard(&builder);
      builder.add(StaticStrings::KeyString, VPackValue(UCFN));
    }

    auto ctx = transaction::V8Context::CreateWhenRequired(vocbase, true);
    SingleCollectionTransaction trx(ctx, StaticStrings::AqlFunctionsCollection, AccessMode::Type::WRITE);

    trx.addHint(transaction::Hints::Hint::SINGLE_OPERATION);

    res = trx.begin();

    if (res.ok()) {
      OperationResult result =
          trx.remove(StaticStrings::AqlFunctionsCollection, builder.slice(), OperationOptions());
      res = trx.finish(result.result);
    }
  }

  if (res.ok()) {
    reloadAqlUserFunctions();
  } else if (res.is(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) {
    return res.reset(TRI_ERROR_QUERY_FUNCTION_NOT_FOUND,
                  std::string("no AQL user function with name '") +
                      functionName + "' found");
  }
  return res;
}

Result arangodb::unregisterUserFunctionsGroup(TRI_vocbase_t& vocbase,
                                              std::string const& functionFilterPrefix,
                                              int& deleteCount) {
  deleteCount = 0;

  if (functionFilterPrefix.empty()) {
    return Result(TRI_ERROR_BAD_PARAMETER);
  }

  if (!isValidFunctionNameFilter(functionFilterPrefix)) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  std::string("error deleting AQL user function: '") +
                      functionFilterPrefix + "' contains invalid characters");
  }

  std::string uc(functionFilterPrefix);
  basics::StringUtils::toupperInPlace(uc);

  if ((uc.length() < 2) || (uc[uc.length() - 1] != ':') || (uc[uc.length() - 2] != ':')) {
    uc += "::";
  }

  auto binds = std::make_shared<VPackBuilder>();
  binds->openObject();
  binds->add("fnLength", VPackValue(uc.length()));
  binds->add("ucName", VPackValue(uc));
  binds->add("@col", VPackValue(StaticStrings::AqlFunctionsCollection));
  binds->close();

  std::string aql(
      "FOR fn IN @@col FILTER UPPER(LEFT(fn.name, @fnLength)) == @ucName "
      "REMOVE { _key: fn._key} in @@col RETURN 1");

  {
    arangodb::aql::Query query(transaction::V8Context::CreateWhenRequired(vocbase, true),
                               arangodb::aql::QueryString(aql), binds, nullptr);
    aql::QueryResult queryResult = query.executeSync();

    if (queryResult.result.fail()) {
      if (queryResult.result.is(TRI_ERROR_REQUEST_CANCELED) ||
          (queryResult.result.is(TRI_ERROR_QUERY_KILLED))) {
        return Result(TRI_ERROR_REQUEST_CANCELED);
      }
      return queryResult.result;
    }

    VPackSlice countSlice = queryResult.data->slice();
    if (!countSlice.isArray()) {
      return Result(TRI_ERROR_INTERNAL,
                    "bad query result for deleting AQL user functions");
    }

    deleteCount = static_cast<int>(countSlice.length());
  }

  reloadAqlUserFunctions();
  return Result();
}

Result arangodb::registerUserFunction(TRI_vocbase_t& vocbase, velocypack::Slice userFunction,
                                      bool& replacedExisting) {
  replacedExisting = false;

  Result res;

  if (!V8DealerFeature::DEALER || !V8DealerFeature::DEALER->isEnabled()) {
    return res.reset(TRI_ERROR_DISABLED, "JavaScript operations are not available");
  }

  std::string name;

  try {
    auto vname = userFunction.get("name");
    if (!vname.isString()) {
      return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                    "function name has to be provided as a string");
    }
    name = vname.copyString();
    if (name.empty()) {
      return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                    "function name has to be provided and must not be empty");
    }
  } catch (...) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  "missing mandatory attribute 'name'");
  }

  if (!isValidFunctionName(name)) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_NAME,
                  std::string("error creating AQL user function: '") + name +
                      "' is not a valid name");
  }

  auto cvString = userFunction.get("code");
  if (!cvString.isString() || cvString.getStringLength() == 0) {
    return Result(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE,
                  "expecting string with function definition");
  }

  std::string tmp = cvString.copyString();
  std::string code = std::string("(") + tmp + "\n)";

  bool isDeterministic = false;
  VPackSlice isDeterministicSlice = userFunction.get("isDeterministic");
  if (isDeterministicSlice.isBoolean()) {
    isDeterministic = isDeterministicSlice.getBoolean();
  }

  {
    ISOLATE;
    bool throwV8Exception = (isolate != nullptr);

    JavaScriptSecurityContext securityContext = JavaScriptSecurityContext::createRestrictedContext();
    V8ConditionalContextGuard contextGuard(res, isolate, &vocbase, securityContext);

    if (res.fail()) {
      return res;
    }

    std::string testCode("(function() { var callback = ");
    testCode += tmp + "; return callback; })()";
    v8::HandleScope scope(isolate);

    v8::Handle<v8::Value> result;
    {
      v8::TryCatch tryCatch(isolate);

      result = TRI_ExecuteJavaScriptString(isolate, isolate->GetCurrentContext(),
                                           TRI_V8_STD_STRING(isolate, testCode),
                                           TRI_V8_ASCII_STRING(isolate,
                                                               "userFunction"),
                                           false);

      if (result.IsEmpty() || !result->IsFunction() || tryCatch.HasCaught()) {
        if (tryCatch.HasCaught()) {
          res.reset(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE,
                    std::string(TRI_errno_string(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE)) +
                        ": " + TRI_StringifyV8Exception(isolate, &tryCatch));

          if (!tryCatch.CanContinue()) {
            if (throwV8Exception) {
              tryCatch.ReThrow();
            }
            TRI_GET_GLOBALS();
            v8g->_canceled = true;
          }
        } else {
          res.reset(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE,
                    std::string(TRI_errno_string(TRI_ERROR_QUERY_FUNCTION_INVALID_CODE)));
        }
      }
    }
  }
  if (!res.ok()) {
    return res;
  }
  std::string _key(name);
  basics::StringUtils::toupperInPlace(_key);

  VPackBuilder oneFunctionDocument;
  oneFunctionDocument.openObject();
  oneFunctionDocument.add(StaticStrings::KeyString, VPackValue(_key));
  oneFunctionDocument.add("name", VPackValue(name));
  oneFunctionDocument.add("code", VPackValue(code));
  oneFunctionDocument.add("isDeterministic", VPackValue(isDeterministic));
  oneFunctionDocument.close();

  {
    arangodb::OperationOptions opOptions;
    opOptions.waitForSync = true;
    opOptions.returnOld = true;
    opOptions.overwriteMode = OperationOptions::OverwriteMode::Replace;

    // find and load collection given by name or identifier
    auto ctx = transaction::V8Context::CreateWhenRequired(vocbase, true);
    SingleCollectionTransaction trx(ctx, StaticStrings::AqlFunctionsCollection, AccessMode::Type::WRITE);

    res = trx.begin();
    if (res.fail()) {
      return res;
    }

    arangodb::OperationResult result =
        trx.insert(StaticStrings::AqlFunctionsCollection, oneFunctionDocument.slice(), opOptions);

    if (result.ok()) {
      VPackSlice oldSlice = result.slice().get(StaticStrings::Old);
      replacedExisting = !(oldSlice.isNone() || oldSlice.isNull());
    }
    // Will commit if no error occured.
    // or abort if an error occured.
    // result stays valid!
    res = trx.finish(result.result);
  }

  if (res.ok()) {
    reloadAqlUserFunctions();
  }

  return res;
}

Result arangodb::toArrayUserFunctions(TRI_vocbase_t& vocbase,
                                      std::string const& functionFilterPrefix,
                                      velocypack::Builder& result) {
  std::string aql;
  auto binds = std::make_shared<VPackBuilder>();

  binds->openObject();

  if (!functionFilterPrefix.empty()) {
    aql =
        "FOR function IN @@col FILTER LEFT(function._key, @fnLength) == "
        "@ucName RETURN function";

    std::string uc(functionFilterPrefix);
    basics::StringUtils::toupperInPlace(uc);

    if ((uc.length() < 2) || (uc[uc.length() - 1] != ':') || (uc[uc.length() - 2] != ':')) {
      uc += "::";
    }

    binds->add("fnLength", VPackValue(uc.length()));
    binds->add("ucName", VPackValue(uc));
  } else {
    aql = "FOR function IN @@col RETURN function";
  }

  binds->add("@col", VPackValue(StaticStrings::AqlFunctionsCollection));
  binds->close();

  arangodb::aql::Query query(transaction::V8Context::CreateWhenRequired(vocbase, true),
                             arangodb::aql::QueryString(aql), binds, nullptr);
  aql::QueryResult queryResult = query.executeSync();

  if (queryResult.result.fail()) {
    if (queryResult.result.is(TRI_ERROR_REQUEST_CANCELED) ||
        (queryResult.result.is(TRI_ERROR_QUERY_KILLED))) {
      return Result(TRI_ERROR_REQUEST_CANCELED);
    }
    return queryResult.result;
  }

  auto usersFunctionsSlice = queryResult.data->slice();

  if (!usersFunctionsSlice.isArray()) {
    return Result(TRI_ERROR_INTERNAL,
                  "bad query result for AQL user functions");
  }

  result.openArray();
  std::string tmp;
  for (VPackSlice it : VPackArrayIterator(usersFunctionsSlice)) {
    VPackSlice resolved;
    resolved = it.resolveExternal();

    if (!resolved.isObject()) {
      return Result(TRI_ERROR_INTERNAL,
                    "element that stores AQL user function is not an object");
    }

    VPackSlice name, fn, dtm;
    bool isDeterministic = false;
    name = resolved.get("name");
    fn = resolved.get("code");
    dtm = resolved.get("isDeterministic");
    if (dtm.isBoolean()) {
      isDeterministic = dtm.getBool();
    }
    // We simply ignore invalid entries in the _functions collection:
    if (name.isString() && fn.isString() && (fn.getStringLength() > 2)) {
      auto ref = arangodb::velocypack::StringRef(fn);

      ref = ref.substr(1, ref.length() - 2);
      tmp = basics::StringUtils::trim(ref.toString());

      VPackBuilder oneFunction;
      oneFunction.openObject();
      oneFunction.add("name", name);
      oneFunction.add("code", VPackValue(tmp));
      oneFunction.add("isDeterministic", VPackValue(isDeterministic));
      oneFunction.close();
      result.add(oneFunction.slice());
    }
  }
  result.close();  // close Array

  return Result();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkSurface.h"
#include "SkCanvas.h"

static void drawContents(SkSurface* surface, SkColor fillC) {
    SkSize size = SkSize::Make(surface->width(), surface->height());
    SkAutoTUnref<SkCanvas> canvas(surface->newCanvas());

    SkScalar stroke = size.fWidth / 10;
    SkScalar radius = (size.fWidth - stroke) / 2;

    SkPaint paint;

    paint.setAntiAlias(true);
    paint.setColor(fillC);
    canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);

    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(stroke);
    paint.setColor(SK_ColorBLACK);
    canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
}

static void test_surface(SkCanvas* canvas, SkSurface* surf) {
    drawContents(surf, SK_ColorRED);
    SkImage* imgR = surf->newImageShapshot();

    drawContents(surf, SK_ColorGREEN);
    SkImage* imgG = surf->newImageShapshot();

    drawContents(surf, SK_ColorBLUE);

    imgR->draw(canvas, 0, 0, NULL);
    imgG->draw(canvas, 0, 80, NULL);
    surf->draw(canvas, 0, 160, NULL);

    imgG->unref();
    imgR->unref();
}

class ImageGM : public skiagm::GM {
    void*   fBuffer;
    size_t  fBufferSize;
    SkSize  fSize;
    enum {
        W = 64,
        H = 64,
        RB = W * 4 + 8,
    };
public:
    ImageGM() {
        fBufferSize = RB * H;
        fBuffer = sk_malloc_throw(fBufferSize);
        fSize.set(SkIntToScalar(W), SkIntToScalar(H));
    }

    virtual ~ImageGM() {
        sk_free(fBuffer);
    }

protected:
    virtual SkString onShortName() {
        return SkString("image");
    }

    virtual SkISize onISize() {
        return SkISize::Make(640, 480);
    }

    virtual void onDraw(SkCanvas* canvas) {
        // since we draw into this directly, we need to start fresh
        sk_bzero(fBuffer, fBufferSize);

        SkImage::Info info;

        info.fWidth = W;
        info.fHeight = H;
        info.fColorType = SkImage::kPMColor_ColorType;
        info.fAlphaType = SkImage::kPremul_AlphaType;
        SkAutoTUnref<SkSurface> surf0(SkSurface::NewRasterDirect(info, NULL, fBuffer, RB));
        SkAutoTUnref<SkSurface> surf1(SkSurface::NewRaster(info, NULL));
        SkAutoTUnref<SkSurface> surf2(SkSurface::NewPicture(info.fWidth, info.fHeight));

        test_surface(canvas, surf0);
        canvas->translate(80, 0);
        test_surface(canvas, surf1);
        canvas->translate(80, 0);
        test_surface(canvas, surf2);
    }

private:
    typedef skiagm::GM INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

static skiagm::GM* MyFactory(void*) { return new ImageGM; }
static skiagm::GMRegistry reg(MyFactory);

<commit_msg>update to surface.getCanvas()<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkSurface.h"
#include "SkCanvas.h"

static void drawContents(SkSurface* surface, SkColor fillC) {
    SkSize size = SkSize::Make(surface->width(), surface->height());
    SkCanvas* canvas = surface->getCanvas();

    SkScalar stroke = size.fWidth / 10;
    SkScalar radius = (size.fWidth - stroke) / 2;

    SkPaint paint;

    paint.setAntiAlias(true);
    paint.setColor(fillC);
    canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);

    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(stroke);
    paint.setColor(SK_ColorBLACK);
    canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
}

static void test_surface(SkCanvas* canvas, SkSurface* surf) {
    drawContents(surf, SK_ColorRED);
    SkImage* imgR = surf->newImageShapshot();

    drawContents(surf, SK_ColorGREEN);
    SkImage* imgG = surf->newImageShapshot();

    drawContents(surf, SK_ColorBLUE);

    SkPaint paint;
//    paint.setFilterBitmap(true);
//    paint.setAlpha(0x80);

    imgR->draw(canvas, 0, 0, &paint);
    imgG->draw(canvas, 0, 80, &paint);
    surf->draw(canvas, 0, 160, &paint);

    imgG->unref();
    imgR->unref();
}

class ImageGM : public skiagm::GM {
    void*   fBuffer;
    size_t  fBufferSize;
    SkSize  fSize;
    enum {
        W = 64,
        H = 64,
        RB = W * 4 + 8,
    };
public:
    ImageGM() {
        fBufferSize = RB * H;
        fBuffer = sk_malloc_throw(fBufferSize);
        fSize.set(SkIntToScalar(W), SkIntToScalar(H));
    }

    virtual ~ImageGM() {
        sk_free(fBuffer);
    }

protected:
    virtual SkString onShortName() {
        return SkString("image");
    }

    virtual SkISize onISize() {
        return SkISize::Make(640, 480);
    }

    virtual void onDraw(SkCanvas* canvas) {
        canvas->translate(10, 10);
        canvas->scale(2, 2);

        // since we draw into this directly, we need to start fresh
        sk_bzero(fBuffer, fBufferSize);

        SkImage::Info info;

        info.fWidth = W;
        info.fHeight = H;
        info.fColorType = SkImage::kPMColor_ColorType;
        info.fAlphaType = SkImage::kPremul_AlphaType;
        SkAutoTUnref<SkSurface> surf0(SkSurface::NewRasterDirect(info, NULL, fBuffer, RB));
        SkAutoTUnref<SkSurface> surf1(SkSurface::NewRaster(info, NULL));
        SkAutoTUnref<SkSurface> surf2(SkSurface::NewPicture(info.fWidth, info.fHeight));

        test_surface(canvas, surf0);
        canvas->translate(80, 0);
        test_surface(canvas, surf1);
        canvas->translate(80, 0);
        test_surface(canvas, surf2);
    }

private:
    typedef skiagm::GM INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

static skiagm::GM* MyFactory(void*) { return new ImageGM; }
static skiagm::GMRegistry reg(MyFactory);

<|endoftext|>


<commit_before>#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>

using namespace cv;
using namespace std;

Mat calculate_energy(Mat I){
	Mat Ix,Iy;

	Sobel(I,Ix,CV_32F,1,0);
	convertScaleAbs(Ix,Ix);

	Sobel(I,Iy,CV_32F,0,1);
	convertScaleAbs(Iy,Iy);

	Mat energy;
	addWeighted(Ix, 0.5, Iy, 0.5, 0, energy);

	return energy;
}

Mat calculate_energy2(Mat I){
	int Y = I.rows,X = I.cols;
	Mat energy = Mat(Y, X, CV_32S);

	for(int x = 0;x < X;++x){
		for(int y = 0;y < Y;++y){
			int val = 0;

			if(x > 0 && x + 1 < X)
				val += abs((int)I.at<uchar>(y,x + 1) - (int)I.at<uchar>(y,x - 1));
			else if(x > 0)
				val += 2 * abs((int)I.at<uchar>(y,x) - (int)I.at<uchar>(y,x - 1));
			else
				val += 2 * abs((int)I.at<uchar>(y,x + 1) - (int)I.at<uchar>(y,x));

			if(y > 0 && y + 1 < Y)
				val += abs((int)I.at<uchar>(y + 1,x) - (int)I.at<uchar>(y - 1,x));
			else if(y > 0)
				val += 2 * abs((int)I.at<uchar>(y,x) - (int)I.at<uchar>(y - 1,x));
			else
				val += 2 * abs((int)I.at<uchar>(y + 1,x) - (int)I.at<uchar>(y,x));

			energy.at<int>(y,x) = val;
		}
	}

	return energy;
}

int main(){
	Mat_<Vec3b> I = imread("../bench.jpg");

	imshow("seam-carving",I);
	waitKey(0);

	int Y = I.rows,X = I.cols;

	Mat gray;
	cvtColor(I,gray,CV_BGR2GRAY);

	Mat energy = calculate_energy(gray);

	imshow("seam-carving",energy);
	waitKey(0);

	unsigned int dpH[X][Y],dpV[X][Y];
	int dirH[X][Y],dirV[X][Y];

	// Horizontal seams

	for(int y = 0;y < Y;++y)
		dpH[0][y] = energy.at<uint>(y,0);

	for(int x = 1;x < X;++x){
		for(int y = 0;y < Y;++y){
			uint val = energy.at<uint>(y,x);
			dpH[x][y] = -1;

			if(y > 0 && (dpH[x][y] == -1 || val + dpH[x - 1][y - 1] < dpH[x][y])){
				dpH[x][y] = val + dpH[x - 1][y - 1];
				dirH[x][y] = -1;
			}

			if(dpH[x][y] == -1 || val + dpH[x - 1][y] < dpH[x][y]){
				dpH[x][y] = val + dpH[x - 1][y];
				dirH[x][y] = 0;
			}

			if(y + 1 < Y && (dpH[x][y] == -1 || val + dpH[x - 1][y + 1] < dpH[x][y])){
				dpH[x][y] = val + dpH[x - 1][y + 1];
				dirH[x][y] = 1;
			}
		}
	}

	Mat seams = I.clone();
	unsigned int bestH = dpH[X - 1][0];
	int cury = 0;

	for(int y = 0;y < Y;++y){
		if(dpH[X - 1][y] < bestH){
			bestH = dpH[X - 1][y];
			cury = y;
		}
	}

	for(int x = X - 1;x >= 0;--x){
		seams.at<Vec3b>(cury,x) = Vec3b(0,0,255);

		if(x > 0)
			cury = cury + dirH[x][cury];
	}

	// Vertical seams

	for(int x = 0;x < X;++x)
		dpV[x][0] = energy.at<uint>(0,x);

	for(int y = 1;y < Y;++y){
		for(int x = 0;x < X;++x){
			uint val = energy.at<uint>(y,x);
			dpV[x][y] = -1;

			if(x > 0 && (dpV[x][y] == -1 || val + dpV[x - 1][y - 1] < dpV[x][y])){
				dpV[x][y] = val + dpV[x - 1][y - 1];
				dirV[x][y] = -1;
			}

			if(dpV[x][y] == -1 || val + dpV[x][y - 1] < dpV[x][y]){
				dpV[x][y] = val + dpV[x][y - 1];
				dirV[x][y] = 0;
			}

			if(x + 1 < X && (dpV[x][y] == -1 || val + dpV[x + 1][y - 1] < dpV[x][y])){
				dpV[x][y] = val + dpV[x + 1][y - 1];
				dirV[x][y] = 1;
			}
		}
	}

	Mat IV = I.clone();
	int bestV = dpV[0][Y - 1];
	int curx = 0;

	for(int x = 0;x < X;++x){
		if(dpV[x][Y - 1] < bestV){
			bestV = dpV[x][Y - 1];
			curx = x;
		}
	}

	for(int y = Y - 1;y >= 0;--y){
		seams.at<Vec3b>(y,curx) = Vec3b(0,0,255);

		if(y > 0)
			curx = curx + dirV[curx][y];
	}

	imshow("seam-carving",seams);
	waitKey(0);

	return 0;
}<commit_msg>reducing size of images<commit_after>#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>

using namespace cv;
using namespace std;

Mat calculate_energy(Mat I){
	Mat Ix,Iy;

	Sobel(I,Ix,CV_32F,1,0);
	convertScaleAbs(Ix,Ix);

	Sobel(I,Iy,CV_32F,0,1);
	convertScaleAbs(Iy,Iy);

	Mat energy;
	addWeighted(Ix, 0.5, Iy, 0.5, 0, energy);

	return energy;
}

Mat calculate_energy2(Mat I){
	int Y = I.rows,X = I.cols;
	Mat energy = Mat(Y, X, CV_32S);

	for(int x = 0;x < X;++x){
		for(int y = 0;y < Y;++y){
			int val = 0;

			if(x > 0 && x + 1 < X)
				val += abs((int)I.at<uchar>(y,x + 1) - (int)I.at<uchar>(y,x - 1));
			else if(x > 0)
				val += 2 * abs((int)I.at<uchar>(y,x) - (int)I.at<uchar>(y,x - 1));
			else
				val += 2 * abs((int)I.at<uchar>(y,x + 1) - (int)I.at<uchar>(y,x));

			if(y > 0 && y + 1 < Y)
				val += abs((int)I.at<uchar>(y + 1,x) - (int)I.at<uchar>(y - 1,x));
			else if(y > 0)
				val += 2 * abs((int)I.at<uchar>(y,x) - (int)I.at<uchar>(y - 1,x));
			else
				val += 2 * abs((int)I.at<uchar>(y + 1,x) - (int)I.at<uchar>(y,x));

			energy.at<int>(y,x) = val;
		}
	}

	return energy;
}

int main(){
	Mat_<Vec3b> I = imread("../beach.jpg");

	imshow("seam-carving",I);
	waitKey(0);

	int Y = I.rows,X = I.cols;

	Mat gray,energy;

	//cvtColor(I,gray,CV_BGR2GRAY);
	//energy = calculate_energy(gray);
	//imshow("seam-carving",energy);
	//waitKey(0);

	unsigned int dpH[X][Y],dpV[X][Y];
	int dirH[X][Y],dirV[X][Y];

	// Horizontal seams

	for(int it = 0;it < 50;++it){
		cvtColor(I,gray,CV_BGR2GRAY);
		energy = calculate_energy(gray);

		for(int y = 0;y < Y;++y)
			dpH[0][y] = energy.at<uint>(y,0);

		for(int x = 1;x < X;++x){
			for(int y = 0;y < Y;++y){
				uint val = energy.at<uint>(y,x);
				dpH[x][y] = -1;

				if(y > 0 && (dpH[x][y] == -1 || val + dpH[x - 1][y - 1] < dpH[x][y])){
					dpH[x][y] = val + dpH[x - 1][y - 1];
					dirH[x][y] = -1;
				}

				if(dpH[x][y] == -1 || val + dpH[x - 1][y] < dpH[x][y]){
					dpH[x][y] = val + dpH[x - 1][y];
					dirH[x][y] = 0;
				}

				if(y + 1 < Y && (dpH[x][y] == -1 || val + dpH[x - 1][y + 1] < dpH[x][y])){
					dpH[x][y] = val + dpH[x - 1][y + 1];
					dirH[x][y] = 1;
				}
			}
		}

		//Mat seams = I.clone();
		unsigned int bestH = dpH[X - 1][0];
		int cury = 0;

		for(int y = 0;y < Y;++y){
			if(dpH[X - 1][y] < bestH){
				bestH = dpH[X - 1][y];
				cury = y;
			}
		}

		Mat_<Vec3b> tmp(Y - 1,X);

		for(int x = X - 1;x >= 0;--x){
			//seams.at<Vec3b>(cury,x) = Vec3b(0,0,255);

			for(int i = 0;i < Y;++i){
				if(i < cury) tmp.at<Vec3b>(i,x) = I.at<Vec3b>(i,x);
				else if(i > cury) tmp.at<Vec3b>(i - 1,x) = I.at<Vec3b>(i,x);
			}

			if(x > 0)
				cury = cury + dirH[x][cury];
		}

		I = tmp;
		--Y;
	}

	// Vertical seams

	for(int it = 0;it < 100;++it){
		for(int x = 0;x < X;++x)
			dpV[x][0] = energy.at<uint>(0,x);

		for(int y = 1;y < Y;++y){
			for(int x = 0;x < X;++x){
				uint val = energy.at<uint>(y,x);
				dpV[x][y] = -1;

				if(x > 0 && (dpV[x][y] == -1 || val + dpV[x - 1][y - 1] < dpV[x][y])){
					dpV[x][y] = val + dpV[x - 1][y - 1];
					dirV[x][y] = -1;
				}

				if(dpV[x][y] == -1 || val + dpV[x][y - 1] < dpV[x][y]){
					dpV[x][y] = val + dpV[x][y - 1];
					dirV[x][y] = 0;
				}

				if(x + 1 < X && (dpV[x][y] == -1 || val + dpV[x + 1][y - 1] < dpV[x][y])){
					dpV[x][y] = val + dpV[x + 1][y - 1];
					dirV[x][y] = 1;
				}
			}
		}

		//Mat IV = I.clone();
		int bestV = dpV[0][Y - 1];
		int curx = 0;

		for(int x = 0;x < X;++x){
			if(dpV[x][Y - 1] < bestV){
				bestV = dpV[x][Y - 1];
				curx = x;
			}
		}

		Mat_<Vec3b> tmp(Y,X - 1);

		for(int y = Y - 1;y >= 0;--y){
			//seams.at<Vec3b>(y,curx) = Vec3b(0,0,255);

			for(int i = 0;i < X;++i){
				if(i < curx) tmp.at<Vec3b>(y,i) = I.at<Vec3b>(y,i);
				else if(i > curx) tmp.at<Vec3b>(y,i - 1) = I.at<Vec3b>(y,i);
			}

			if(y > 0)
				curx = curx + dirV[curx][y];
		}

		I = tmp;
		--X;
	}

	//imshow("seam-carving",seams);
	imshow("seam-carving-out",I);
	waitKey(0);

	return 0;
}<|endoftext|>