text:
#include <stan/math/rev/mat.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/rev/mat/fun/util.hpp>
#include <test/unit/math/rev/mat/util.hpp>

#ifdef STAN_OPENCL
#include <boost/random/mersenne_twister.hpp>
#endif

TEST(AgradRevMatrix, mdivide_left_tri_val) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;

  matrix_v Av(2, 2);
  matrix_v Av_inv(2, 2);
  matrix_d Ad(2, 2);
  matrix_v I;

  Av << 2.0, 0.0, 5.0, 7.0;
  Ad << 2.0, 0.0, 5.0, 7.0;

  I = mdivide_left_tri<Eigen::Lower>(Av, Av);
  EXPECT_NEAR(1.0, I(0, 0).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0).val(), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1).val(), 1.0e-12);

  I = mdivide_left_tri<Eigen::Lower>(Av, Ad);
  EXPECT_NEAR(1.0, I(0, 0).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0).val(), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1).val(), 1.0e-12);

  I = mdivide_left_tri<Eigen::Lower>(Ad, Av);
  EXPECT_NEAR(1.0, I(0, 0).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0).val(), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1).val(), 1.0e-12);

  Av_inv = mdivide_left_tri<Eigen::Lower>(Av);
  I = Av * Av_inv;
  EXPECT_NEAR(1.0, I(0, 0).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0).val(), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1).val(), 1.0e-12);

  Av << 2.0, 3.0, 0.0, 7.0;
  Ad << 2.0, 3.0, 0.0, 7.0;

  I = mdivide_left_tri<Eigen::Upper>(Av, Av);
  EXPECT_NEAR(1.0, I(0, 0).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0).val(), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1).val(), 1.0e-12);

  I = mdivide_left_tri<Eigen::Upper>(Av, Ad);
  EXPECT_NEAR(1.0, I(0, 0).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0).val(), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1).val(), 1.0e-12);

  I = mdivide_left_tri<Eigen::Upper>(Ad, Av);
  EXPECT_NEAR(1.0, I(0, 0).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1).val(), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0).val(), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1).val(), 1.0e-12);
}

TEST(AgradRevMatrix, mdivide_left_tri_lower_grad_vv) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;

  matrix_d Ad(2, 2), Ad_tmp(2, 2);
  matrix_d Bd(2, 2), Bd_tmp(2, 2);
  matrix_d Cd(2, 2);

  Ad << 2.0, 0.0, 5.0, 7.0;
  Bd << 12.0, 13.0, 15.0, 17.0;

  size_type i, j, k, l;
  for (i = 0; i < Bd.rows(); i++) {
    for (j = 0; j < Bd.cols(); j++) {
      matrix_v A(2, 2);
      matrix_v B(2, 2);
      matrix_v C;
      VEC g;

      for (k = 0; k < 4; k++) {
        A(k) = Ad(k);
        B(k) = Bd(k);
      }

      C = mdivide_left_tri<Eigen::Lower>(A, B);
      AVEC x = createAVEC(A(0, 0), A(1, 0), A(0, 1), A(1, 1), B(0, 0), B(1, 0),
                          B(0, 1), B(1, 1));
      C(i, j).grad(x, g);

      for (l = 0; l < Ad_tmp.cols(); l++) {
        for (k = 0; k < Ad_tmp.rows(); k++) {
          if (k >= l) {
            Ad_tmp.setZero();
            Ad_tmp(k, l) = 1.0;
            Cd = -mdivide_left_tri<Eigen::Lower>(
                Ad, multiply(Ad_tmp, mdivide_left_tri<Eigen::Lower>(Ad, Bd)));
            EXPECT_NEAR(Cd(i, j), g[k + l * Ad_tmp.rows()], 1.0E-12);
          } else {
            EXPECT_NEAR(0.0, g[k + l * Ad_tmp.rows()], 1.0E-12);
          }
        }
      }
      for (k = 0; k < 4; k++) {
        Bd_tmp.setZero();
        Bd_tmp(k) = 1.0;
        Cd = mdivide_left_tri<Eigen::Lower>(Ad, Bd_tmp);
        EXPECT_NEAR(Cd(i, j), g[4 + k], 1.0E-12);
      }
    }
  }
}

TEST(AgradRevMatrix, mdivide_left_tri_lower_grad_dv) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;

  matrix_d Ad(2, 2), Ad_tmp(2, 2);
  matrix_d Bd(2, 2), Bd_tmp(2, 2);
  matrix_d Cd(2, 2);

  Ad << 2.0, 0.0, 5.0, 7.0;
  Bd << 12.0, 13.0, 15.0, 17.0;

  size_type i, j, k;
  for (i = 0; i < Bd.rows(); i++) {
    for (j = 0; j < Bd.cols(); j++) {
      matrix_v B(2, 2);
      matrix_v C;
      VEC g;

      for (k = 0; k < 4; k++) {
        B(k) = Bd(k);
      }

      C = mdivide_left_tri<Eigen::Lower>(Ad, B);
      AVEC x = createAVEC(B(0, 0), B(1, 0), B(0, 1), B(1, 1));
      C(i, j).grad(x, g);

      for (k = 0; k < 4; k++) {
        Bd_tmp.setZero();
        Bd_tmp(k) = 1.0;
        Cd = mdivide_left_tri<Eigen::Lower>(Ad, Bd_tmp);
        EXPECT_NEAR(Cd(i, j), g[k], 1.0E-12);
      }
    }
  }
}

TEST(AgradRevMatrix, mdivide_left_tri_lower_grad_vd) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;

  matrix_d Ad(2, 2), Ad_tmp(2, 2);
  matrix_d Bd(2, 2), Bd_tmp(2, 2);
  matrix_d Cd(2, 2);

  Ad << 2.0, 0.0, 5.0, 7.0;
  Bd << 12.0, 13.0, 15.0, 17.0;

  size_type i, j, k, l;
  for (i = 0; i < Bd.rows(); i++) {
    for (j = 0; j < Bd.cols(); j++) {
      matrix_v A(2, 2);
      matrix_v C;
      VEC g;

      for (k = 0; k < 4; k++) {
        A(k) = Ad(k);
      }

      C = mdivide_left_tri<Eigen::Lower>(A, Bd);
      AVEC x = createAVEC(A(0, 0), A(1, 0), A(0, 1), A(1, 1));
      C(i, j).grad(x, g);

      for (l = 0; l < Ad_tmp.cols(); l++) {
        for (k = 0; k < Ad_tmp.rows(); k++) {
          if (k >= l) {
            Ad_tmp.setZero();
            Ad_tmp(k, l) = 1.0;
            Cd = -mdivide_left_tri<Eigen::Lower>(
                Ad, multiply(Ad_tmp, mdivide_left_tri<Eigen::Lower>(Ad, Bd)));
            EXPECT_NEAR(Cd(i, j), g[k + l * Ad_tmp.rows()], 1.0E-12);
          } else {
            EXPECT_NEAR(0.0, g[k + l * Ad_tmp.rows()], 1.0E-12);
          }
        }
      }
    }
  }
}
TEST(AgradRevMatrix, mdivide_left_tri_upper_grad_vv) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;

  matrix_d Ad(2, 2), Ad_tmp(2, 2);
  matrix_d Bd(2, 2), Bd_tmp(2, 2);
  matrix_d Cd(2, 2);

  Ad << 2.0, 3.0, 0.0, 7.0;
  Bd << 12.0, 13.0, 15.0, 17.0;

  size_type i, j, k, l;
  for (i = 0; i < Bd.rows(); i++) {
    for (j = 0; j < Bd.cols(); j++) {
      matrix_v A(2, 2);
      matrix_v B(2, 2);
      matrix_v C;
      VEC g;

      for (k = 0; k < 4; k++) {
        A(k) = Ad(k);
        B(k) = Bd(k);
      }

      C = mdivide_left_tri<Eigen::Upper>(A, B);
      AVEC x = createAVEC(A(0, 0), A(1, 0), A(0, 1), A(1, 1), B(0, 0), B(1, 0),
                          B(0, 1), B(1, 1));
      C(i, j).grad(x, g);

      for (l = 0; l < Ad_tmp.cols(); l++) {
        for (k = 0; k < Ad_tmp.rows(); k++) {
          if (k <= l) {
            Ad_tmp.setZero();
            Ad_tmp(k, l) = 1.0;
            Cd = -mdivide_left_tri<Eigen::Upper>(
                Ad, multiply(Ad_tmp, mdivide_left_tri<Eigen::Upper>(Ad, Bd)));
            EXPECT_NEAR(Cd(i, j), g[k + l * Ad_tmp.rows()], 1.0E-12);
          } else {
            EXPECT_NEAR(0.0, g[k + l * Ad_tmp.rows()], 1.0E-12);
          }
        }
      }
      for (k = 0; k < 4; k++) {
        Bd_tmp.setZero();
        Bd_tmp(k) = 1.0;
        Cd = mdivide_left_tri<Eigen::Upper>(Ad, Bd_tmp);
        EXPECT_NEAR(Cd(i, j), g[4 + k], 1.0E-12);
      }
    }
  }
}

TEST(AgradRevMatrix, mdivide_left_tri_upper_grad_dv) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;

  matrix_d Ad(2, 2), Ad_tmp(2, 2);
  matrix_d Bd(2, 2), Bd_tmp(2, 2);
  matrix_d Cd(2, 2);

  Ad << 2.0, 3.0, 0.0, 7.0;
  Bd << 12.0, 13.0, 15.0, 17.0;

  size_type i, j, k;
  for (i = 0; i < Bd.rows(); i++) {
    for (j = 0; j < Bd.cols(); j++) {
      matrix_v B(2, 2);
      matrix_v C;
      VEC g;

      for (k = 0; k < 4; k++) {
        B(k) = Bd(k);
      }

      C = mdivide_left_tri<Eigen::Upper>(Ad, B);
      AVEC x = createAVEC(B(0, 0), B(1, 0), B(0, 1), B(1, 1));
      C(i, j).grad(x, g);

      for (k = 0; k < 4; k++) {
        Bd_tmp.setZero();
        Bd_tmp(k) = 1.0;
        Cd = mdivide_left_tri<Eigen::Upper>(Ad, Bd_tmp);
        EXPECT_NEAR(Cd(i, j), g[k], 1.0E-12);
      }
    }
  }
}

TEST(AgradRevMatrix, mdivide_left_tri_upper_grad_vd) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;

  matrix_d Ad(2, 2), Ad_tmp(2, 2);
  matrix_d Bd(2, 2), Bd_tmp(2, 2);
  matrix_d Cd(2, 2);

  Ad << 2.0, 3.0, 0.0, 7.0;
  Bd << 12.0, 13.0, 15.0, 17.0;

  size_type i, j, k, l;
  for (i = 0; i < Bd.rows(); i++) {
    for (j = 0; j < Bd.cols(); j++) {
      matrix_v A(2, 2);
      matrix_v C;
      VEC g;

      for (k = 0; k < 4; k++) {
        A(k) = Ad(k);
      }

      C = mdivide_left_tri<Eigen::Upper>(A, Bd);
      AVEC x = createAVEC(A(0, 0), A(1, 0), A(0, 1), A(1, 1));
      C(i, j).grad(x, g);

      for (l = 0; l < Ad_tmp.cols(); l++) {
        for (k = 0; k < Ad_tmp.rows(); k++) {
          if (k <= l) {
            Ad_tmp.setZero();
            Ad_tmp(k, l) = 1.0;
            Cd = -mdivide_left_tri<Eigen::Upper>(
                Ad, multiply(Ad_tmp, mdivide_left_tri<Eigen::Upper>(Ad, Bd)));
            EXPECT_NEAR(Cd(i, j), g[k + l * Ad_tmp.rows()], 1.0E-12);
          } else {
            EXPECT_NEAR(0.0, g[k + l * Ad_tmp.rows()], 1.0E-12);
          }
        }
      }
    }
  }
}

TEST(AgradRevMatrix, check_varis_on_stack) {
  using stan::math::value_of;
  stan::math::matrix_v A(2, 2);
  A << 2.0, 0.0, 5.0, 7.0;

  test::check_varis_on_stack(stan::math::mdivide_left_tri<Eigen::Lower>(A, A));
  test::check_varis_on_stack(
      stan::math::mdivide_left_tri<Eigen::Lower>(A, value_of(A)));
  test::check_varis_on_stack(
      stan::math::mdivide_left_tri<Eigen::Lower>(value_of(A), A));
}

#ifdef STAN_OPENCL
#define EXPECT_MATRIX_NEAR(A, B, DELTA) \
  for (int i = 0; i < A.size(); i++)    \
    EXPECT_NEAR(stan::math::value_of(A(i)), stan::math::value_of(B(i)), DELTA);

boost::random::mt19937 rng;
#define MDIVIDE_OPENCL_OVERRIDE 0
#define MDIVIDE_CPU_OVERRIDE INT_MAX
TEST(AgradRevMatrix, mdivide_left_tri_val_cl) {
  int temp = stan::math::opencl_context.tuning_opts()
                 .tri_inverse_size_worth_transfer;
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  int size = 111;
  matrix_v Av(size, size);
  matrix_d Ad(size, size);
  matrix_v I, I_cl;
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Ad(i, j) = stan::math::uniform_rng(-5, 5, rng);
      Av(i, j) = Ad(i, j);
    }
    Ad(i, i) = 20.0;
    Av(i, i) = Ad(i, i);
    for (int j = i + 1; j < size; j++) {
      Ad(i, j) = 0.0;
      Av(i, j) = Ad(i, j);
    }
  }
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  I_cl = mdivide_left_tri<Eigen::Lower>(Av, Av);
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  I = mdivide_left_tri<Eigen::Lower>(Av, Av);
  EXPECT_MATRIX_NEAR(I, I_cl, 1.0E-12);

  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  I_cl = mdivide_left_tri<Eigen::Lower>(Av, Ad);
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  I = mdivide_left_tri<Eigen::Lower>(Av, Ad);
  EXPECT_MATRIX_NEAR(I, I_cl, 1.0E-12);

  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  I_cl = mdivide_left_tri<Eigen::Lower>(Ad, Av);
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  I = mdivide_left_tri<Eigen::Lower>(Ad, Av);
  EXPECT_MATRIX_NEAR(I, I_cl, 1.0E-12);

  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  matrix_v Av_inv_cl = mdivide_left_tri<Eigen::Lower>(Av);
  I_cl = Av * Av_inv_cl;
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  matrix_v Av_inv = mdivide_left_tri<Eigen::Lower>(Av);
  I = Av * Av_inv;
  EXPECT_MATRIX_NEAR(I, I_cl, 1.0E-12);

  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Ad(i, j) = 0.0;
      Av(i, j) = Ad(i, j);
    }
    Ad(i, i) = 20.0;
    Av(i, i) = Ad(i, i);
    for (int j = i + 1; j < size; j++) {
      Ad(i, j) = stan::math::uniform_rng(-5, 5, rng);
      Av(i, j) = Ad(i, j);
    }
  }

  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  I_cl = mdivide_left_tri<Eigen::Upper>(Av, Av);
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  I = mdivide_left_tri<Eigen::Upper>(Av, Av);
  EXPECT_MATRIX_NEAR(I, I_cl, 1.0E-12);

  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  I_cl = mdivide_left_tri<Eigen::Upper>(Av, Ad);
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  I = mdivide_left_tri<Eigen::Upper>(Av, Ad);
  EXPECT_MATRIX_NEAR(I, I_cl, 1.0E-12);

  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  I_cl = mdivide_left_tri<Eigen::Upper>(Ad, Av);
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  I = mdivide_left_tri<Eigen::Upper>(Ad, Av);
  EXPECT_MATRIX_NEAR(I, I_cl, 1.0E-12);

  // restore default value
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = temp;
}

TEST(AgradRevMatrix, mdivide_left_tri_lower_grad_vv_cl) {
  int temp = stan::math::opencl_context.tuning_opts()
                 .tri_inverse_size_worth_transfer;

  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;
  int size = 256;

  matrix_v Av(size, size);
  matrix_v Bv(size, size);
  matrix_v Cv(size, size);
  matrix_v Cv_cl(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Av(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    Av(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      Av(i, j) = 0.0;
    }
    for (int j = 0; j < size; j++) {
      Bv(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  Cv_cl = mdivide_left_tri<Eigen::Lower>(Av, Bv);
  Cv_cl(0, 0).grad();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  Cv = mdivide_left_tri<Eigen::Lower>(Av, Bv);
  Cv(0, 0).grad();
  EXPECT_MATRIX_NEAR(Cv, Cv_cl, 1.0E-12);
  EXPECT_MATRIX_NEAR(Cv.adj(), Cv_cl.adj(), 1.0E-12);
  stan::math::recover_memory();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = temp;
}

TEST(AgradRevMatrix, mdivide_left_tri_lower_grad_dv_cl) {
  int temp = stan::math::opencl_context.tuning_opts()
                 .tri_inverse_size_worth_transfer;

  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;
  int size = 213;

  matrix_d Ad(size, size);
  matrix_v Bv(size, size);
  matrix_v Cv(size, size);
  matrix_v Cv_cl(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Ad(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    Ad(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      Ad(i, j) = 0.0;
    }
    for (int j = 0; j < size; j++) {
      Bv(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  Cv_cl = mdivide_left_tri<Eigen::Lower>(Ad, Bv);
  Cv_cl(0, 0).grad();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  Cv = mdivide_left_tri<Eigen::Lower>(Ad, Bv);
  Cv(0, 0).grad();
  EXPECT_MATRIX_NEAR(Cv, Cv_cl, 1.0E-12);
  EXPECT_MATRIX_NEAR(Cv.adj(), Cv_cl.adj(), 1.0E-12);
  stan::math::recover_memory();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = temp;
}

TEST(AgradRevMatrix, mdivide_left_tri_lower_grad_vd_cl) {
  int temp = stan::math::opencl_context.tuning_opts()
                 .tri_inverse_size_worth_transfer;

  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;
  int size = 250;

  matrix_d Av(size, size);
  matrix_v Bd(size, size);
  matrix_v Cv(size, size);
  matrix_v Cv_cl(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Av(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    Av(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      Av(i, j) = 0.0;
    }
    for (int j = 0; j < size; j++) {
      Bd(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  Cv_cl = mdivide_left_tri<Eigen::Lower>(Av, Bd);
  Cv_cl(0, 0).grad();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  Cv = mdivide_left_tri<Eigen::Lower>(Av, Bd);
  Cv(0, 0).grad();
  EXPECT_MATRIX_NEAR(Cv, Cv_cl, 1.0E-12);
  EXPECT_MATRIX_NEAR(Cv.adj(), Cv_cl.adj(), 1.0E-12);
  stan::math::recover_memory();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = temp;
}

TEST(AgradRevMatrix, mdivide_left_tri_upper_grad_vv_cl) {
  int temp = stan::math::opencl_context.tuning_opts()
                 .tri_inverse_size_worth_transfer;

  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;
  int size = 299;

  matrix_v Av(size, size);
  matrix_v Bv(size, size);
  matrix_v Cv(size, size);
  matrix_v Cv_cl(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Av(i, j) = 0.0;
    }
    Av(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      Av(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    for (int j = 0; j < size; j++) {
      Bv(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  Cv_cl = mdivide_left_tri<Eigen::Upper>(Av, Bv);
  Cv_cl(0, 0).grad();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  Cv = mdivide_left_tri<Eigen::Upper>(Av, Bv);
  Cv(0, 0).grad();
  EXPECT_MATRIX_NEAR(Cv, Cv_cl, 1.0E-12);
  EXPECT_MATRIX_NEAR(Cv.adj(), Cv_cl.adj(), 1.0E-12);
  stan::math::recover_memory();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = temp;
}

TEST(AgradRevMatrix, mdivide_left_tri_upper_grad_dv_cl) {
  int temp = stan::math::opencl_context.tuning_opts()
                 .tri_inverse_size_worth_transfer;

  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;
  int size = 301;

  matrix_d Ad(size, size);
  matrix_v Bv(size, size);
  matrix_v Cv(size, size);
  matrix_v Cv_cl(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Ad(i, j) = 0.0;
    }
    Ad(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      Ad(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    for (int j = 0; j < size; j++) {
      Bv(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  Cv_cl = mdivide_left_tri<Eigen::Upper>(Ad, Bv);
  Cv_cl(0, 0).grad();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  Cv = mdivide_left_tri<Eigen::Upper>(Ad, Bv);
  Cv(0, 0).grad();
  EXPECT_MATRIX_NEAR(Cv, Cv_cl, 1.0E-12);
  EXPECT_MATRIX_NEAR(Cv.adj(), Cv_cl.adj(), 1.0E-12);
  stan::math::recover_memory();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = temp;
}

TEST(AgradRevMatrix, mdivide_left_tri_upper_grad_vd_cl) {
  int temp = stan::math::opencl_context.tuning_opts()
                 .tri_inverse_size_worth_transfer;

  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::mdivide_left_tri;
  using stan::math::multiply;
  int size = 300;

  matrix_d Av(size, size);
  matrix_v Bd(size, size);
  matrix_v Cv(size, size);
  matrix_v Cv_cl(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      Av(i, j) = 0.0;
    }
    Av(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      Av(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    for (int j = 0; j < size; j++) {
      Bd(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_OPENCL_OVERRIDE;
  Cv_cl = mdivide_left_tri<Eigen::Upper>(Av, Bd);
  Cv_cl(0, 0).grad();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = MDIVIDE_CPU_OVERRIDE;
  Cv = mdivide_left_tri<Eigen::Upper>(Av, Bd);
  Cv(0, 0).grad();
  EXPECT_MATRIX_NEAR(Cv, Cv_cl, 1.0E-12);
  EXPECT_MATRIX_NEAR(Cv.adj(), Cv_cl.adj(), 1.0E-12);
  stan::math::recover_memory();
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = temp;
}
#endif

max_stars_repo_name: PhilClemson/math

max_issues_repo_name: PhilClemson/math

max_forks_repo_name: alashworth/stan-monorepo


text:
#include <boost/asio/io_service.hpp>
#include <riakpp/blocking_group.hpp>
#include <riakpp/client.hpp>

int example1() {
  riak::client client{"localhost", 8087};

  client.async_store("example_bucket", "example_key", "hello, world!",
                     [&](std::error_code error) {
                        if (error) std::cerr << error.message() << ".\n";
                        client.stop_managed();  // Unblocks main thread.
                      });
  client.run_managed();  // Block until client.stop_managed().
  return 0;
}

int example2() {
  boost::asio::io_service io_service;
  boost::asio::io_service::work work{io_service};
  riak::client client{io_service, "localhost", 8087};

  client.async_store("example_bucket", "example_key", "hello, world!",
                     [&](std::error_code error) {
                        if (error) std::cerr << error.message() << ".\n";
                        io_service.stop();
                      });
  io_service.run();
  return 0;
}

int example3() {
  riak::client client{"localhost", 8087};

  riak::blocking_group blocker;
  std::error_code error;
  client.async_store("example_bucket", "example_key", "hello, world!",
                     blocker.wrap([&](std::error_code store_error) {
                       error = store_error;  // Save to variable outside scope.
                     }));

  // Wait until all the wrapped handlers have been called.
  blocker.wait();
  if (error) { std::cerr << error.message() << std::endl; return 1; }
  blocker.reset();  // Reset the group to allow reuse.

  // Wrapping a handler just to save a variable would be cumbersome, so you
  // use for convenience, you can replace
  //    blocker.wrap([&] (type1 arg1, type2 arg2, ...) {
  //      var1 = arg1;
  //      var2 = arg2;
  //      ...
  //    });
  // with blocker.save(var1, var2, ...). For instance, the fetch handler has
  // signature void(std::error_code, riak::object), hence we can write:
  riak::object fetched{"example_bucket", "example_key"};
  client.async_fetch(fetched, blocker.save(error, fetched));
  blocker.wait();
  if (error) { std::cerr << error.message() << std::endl; return 1; }
  blocker.reset();

  std::cout << "Fetched value '" << fetched.value() << "'." << std::endl;

  // Finally, let's remove the object. Again we can use save() to get the error.
  client.async_remove(fetched, blocker.save(error));
  blocker.wait();
  if (error) { std::cerr << error.message() << std::endl; return 1; }

  // Notice we don't reset blocker again. If a 'pending' blocking_group is
  // destroyed the process is aborted -- think of it as destroying an unjoined
  // thread. A blocking_group is pending when it accepts calls to wrap() and
  // wait(): after construction or after a call to reset() and stops being
  // pending after a call to wait().
  //
  // Redundant calls to wait() are OK and simply don't do anything.
  return 0;
}

int example4() {
  riak::client client{"localhost", 8087};

  // Nested lambdas to fetch, modify and store the object.
  std::error_code exit_with;
  client.async_fetch(
      "example_bucket", "example_key",
      [&](std::error_code fetch_error, riak::object fetched) {
        if (fetch_error) {
          exit_with = fetch_error;
          client.stop_managed();
          return;
        }
        fetched.value() = "hello, world!";
        client.async_store(fetched,
                           [&](std::error_code store_error) {
                             exit_with = store_error;
                             client.stop_managed();
                           });
      });
  client.run_managed();  // Block until client.managed_stop().

  if (exit_with) {
    std::cerr << "Error: " << exit_with.message() << std::endl;
    return 1;
  }
  return 0;
}

riak::store_resolved_sibling max_length_resolution(riak::object& conflicted) {
  size_t max_length = 0;
  const riak::object::content* max_length_sibling = nullptr;
  for (auto& sibling : conflicted.siblings()) {
    if (sibling.value().length() >= max_length) {
      max_length = sibling.value().length();
      max_length_sibling = &sibling;
    }
  }
  conflicted.resolve_with(*max_length_sibling);

  // Returning yes means we want riakpp to make a store() call with the resolved
  // object before calling the fetch handler.
  return riak::store_resolved_sibling::yes;
}

int example5() {
  riak::client client{"localhost", 8087, &max_length_resolution};

  // Nested lambdas to fetch, modify and store the object.
  std::error_code exit_with;
  client.async_fetch(
      "example_bucket", "example_key",
      [&](std::error_code fetch_error, riak::object fetched) {
        if (fetch_error) {
          exit_with = fetch_error;
          client.stop_managed();
          return;
        }
        fetched.value() = "hello, world!";
        client.async_store(fetched,
                           [&](std::error_code store_error) {
                             exit_with = store_error;
                             client.stop_managed();
                           });
      });
  client.run_managed();  // Block until client.managed_stop().

  if (exit_with) {
    std::cerr << "Error: " << exit_with.message() << std::endl;
    return 1;
  }
  return 0;
}

int main() {
  int error;
  error = example1(); if (error) return error;
  error = example2(); if (error) return error;
  error = example3(); if (error) return error;
  error = example4(); if (error) return error;
  return 0;
}

ext: cpp

max_stars_repo_name: cristicbz/riakpp

max_issues_repo_name: cristicbz/riakpp

max_forks_repo_name: cristicbz/riakpp


text:
// Copyright 2022 Dennis Hezel
//
// 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.

#include "protos/helloworld.grpc.pb.h"

#include <agrpc/asioGrpc.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/signal_set.hpp>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>

#include <optional>
#include <thread>

int main(int argc, const char** argv)
{
    const auto port = argc >= 2 ? argv[1] : "50051";
    const auto host = std::string("0.0.0.0:") + port;

    // begin-snippet: server-side-helloworld
    grpc::ServerBuilder builder;
    std::unique_ptr<grpc::Server> server;
    helloworld::Greeter::AsyncService service;
    agrpc::GrpcContext grpc_context{builder.AddCompletionQueue()};
    builder.AddListeningPort(host, grpc::InsecureServerCredentials());
    builder.RegisterService(&service);
    server = builder.BuildAndStart();

    boost::asio::co_spawn(
        grpc_context,
        [&]() -> boost::asio::awaitable<void>
        {
            grpc::ServerContext server_context;
            helloworld::HelloRequest request;
            grpc::ServerAsyncResponseWriter<helloworld::HelloReply> writer{&server_context};
            co_await agrpc::request(&helloworld::Greeter::AsyncService::RequestSayHello, service, server_context,
                                    request, writer);
            helloworld::HelloReply response;
            response.set_message("Hello " + request.name());
            co_await agrpc::finish(writer, response, grpc::Status::OK);
        },
        boost::asio::detached);

    grpc_context.run();
    // end-snippet

    server->Shutdown();
}

max_stars_repo_name: Tradias/asio-grpc

max_issues_repo_name: Tradias/asio-grpc

max_forks_repo_name: Tradias/asio-grpc


text:
#pragma once

#include <cstdint>
#include <fstream>
#include <functional>
#include <string>
#include <unordered_map>
#include <utility>

#include <boost/optional.hpp>

#include "3party/jansson/myjansson.hpp"

namespace generator
{
using KeyValue = std::pair<uint64_t, base::Json>;

class KeyValueStorage
{
public:
  explicit KeyValueStorage(std::string const & kvPath,
                           std::function<bool(KeyValue const &)> const & pred = DefaultPred);

  KeyValueStorage(KeyValueStorage &&) = default;
  KeyValueStorage & operator=(KeyValueStorage &&) = default;

  KeyValueStorage(KeyValueStorage const &) = delete;
  KeyValueStorage & operator=(KeyValueStorage const &) = delete;

  boost::optional<base::Json> Find(uint64_t key) const;
  size_t Size() const;

private:
  static bool DefaultPred(KeyValue const &) { return true; }
  static bool ParseKeyValueLine(std::string const & line, KeyValue & res, std::streamoff lineNumber);

  std::unordered_map<uint64_t, base::Json> m_values;
};
}  // namespace generator

ext: hpp

max_stars_repo_name: letko-dmitry/omim

max_issues_repo_name: Mahmoudabdelmobdy/omim

max_forks_repo_name: Mahmoudabdelmobdy/omim


text:
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "rotation_matrix_from_directions.h"
#include <Eigen/Geometry>
#include <iostream>

template <typename Scalar>
IGL_INLINE Eigen::Matrix<Scalar, 3, 3> igl::rotation_matrix_from_directions(
  const Eigen::Matrix<Scalar, 3, 1> v0,
  const Eigen::Matrix<Scalar, 3, 1> v1)
{
  Eigen::Matrix<Scalar, 3, 3> rotM;
  const double epsilon=1e-8;
  Scalar dot=v0.normalized().dot(v1.normalized());
  ///control if there is no rotation
  if ((v0-v1).norm()<epsilon)
  {
    rotM = Eigen::Matrix<Scalar, 3, 3>::Identity();
    return rotM;
  }
  if ((v0+v1).norm()<epsilon)
  {
    rotM = -Eigen::Matrix<Scalar, 3, 3>::Identity();
    rotM(0,0) = 1.;
    std::cerr<<"igl::rotation_matrix_from_directions: rotating around x axis by 180o"<<std::endl;
    return rotM;
  }
  ///find the axis of rotation
  Eigen::Matrix<Scalar, 3, 1> axis;
  axis=v0.cross(v1);
  axis.normalize();

  ///construct rotation matrix
  Scalar u=axis(0);
  Scalar v=axis(1);
  Scalar w=axis(2);
  Scalar phi=acos(dot);
  Scalar rcos = cos(phi);
  Scalar rsin = sin(phi);

  rotM(0,0) =      rcos + u*u*(1-rcos);
  rotM(1,0) =  w * rsin + v*u*(1-rcos);
  rotM(2,0) = -v * rsin + w*u*(1-rcos);
  rotM(0,1) = -w * rsin + u*v*(1-rcos);
  rotM(1,1) =      rcos + v*v*(1-rcos);
  rotM(2,1) =  u * rsin + w*v*(1-rcos);
  rotM(0,2) =  v * rsin + u*w*(1-rcos);
  rotM(1,2) = -u * rsin + v*w*(1-rcos);
  rotM(2,2) =      rcos + w*w*(1-rcos);

  return rotM;
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template Eigen::Matrix<double, 3, 3, 0, 3, 3> igl::rotation_matrix_from_directions<double>(const Eigen::Matrix<double, 3, 1, 0, 3, 1>, const Eigen::Matrix<double, 3, 1, 0, 3, 1>);
#endif


text:
#include <stdlib.h>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <thread>
#include <chrono>
#include <iostream>
using namespace boost;
using namespace std;
void writeToSocket(asio::ip::tcp::socket& sock, std::string& buf) {  // Запись данных в сокет
	std::size_t total_bytes_written = 0;
	while (total_bytes_written != buf.length()) {
		total_bytes_written += sock.write_some(
			asio::buffer(buf.c_str() +
			total_bytes_written,
			buf.length() - total_bytes_written));
	}
}

bool flag = true; // Флаг работы клиента

// Потоковая функция клиент
void ClientThread(string clientName) // Параметр функции - имя клиента
{
	std::string raw_ip_address = "127.0.0.1"; // Адрес сервера - локальеный компьютер (localhost)
	unsigned short port_num = 3333; // Номер порта
	asio::ip::tcp::endpoint ep(asio::ip::address::from_string(raw_ip_address),	port_num); // Создаем точку доступа
	asio::io_service ios;
	asio::ip::tcp::socket sock(ios, ep.protocol()); // Создаем сокет клиента
	sock.connect(ep); // подключение сокета к точке доступа

	// Отправляем данные серверу
	string strToServ = clientName;  // Первый раз отправляем имя клиент
	cout << "To server: " << strToServ << endl; // Печать данных отправляемых на сервер
	writeToSocket(sock, strToServ); // Отвправка - запись в сокет
	// Получаем ответ сервера
	boost::array<char, 256> buf; // Буфер для приема сообщения от сервера
	boost::system::error_code error; // Суда записываем код ошибки (не используем)
	size_t len = sock.read_some(boost::asio::buffer(buf), error); // Читаем данные от сервера
	buf[len] = 0; // Строка заканчивается 0
	cout  << "From server: " << buf.data(); // Печать данных от сервера
	while (flag) // В цикле посылаем запрос, получаем ответ
	{
		switch (rand() % 3 + 1) // Случайно выбирает тип запроса
		{
		case 1:	strToServ = "ping\n"; break;
		case 2:	strToServ = "clients\n"; break;
		case 3:	strToServ = "Hernауауцya\n"; break;
		}
		cout << "To server: " << strToServ ; // Печать данных отправляемых на сервер
		writeToSocket(sock, strToServ); // Отвправка - запись в сокет
		// Получаем ответ сервера
		size_t len = sock.read_some(boost::asio::buffer(buf), error); // Читаем данные от сервера
		buf[len] = 0; // Строка заканчивается 0
		cout << "From server: " << buf.data() ; // Печать данных от сервера
		this_thread::sleep_for(chrono::seconds(1)); // Задержка 1 сек
	}

	// Завершение приема передачи, закрытие сокета
	sock.shutdown(asio::socket_base::shutdown_send);
	// Close socket (is done by dtor)
	sock.close();

}

// Приложение клиент
void main()
{

	// Создаем потоки динамически
	cout << "For start thread, press Enter!\n";
	cout << "For exit, press Enter!\n";
	cin.get(); // Ждем нажатия Enter
	thread t1(ClientThread, "MyClient145");
	cout << "Thread1 Start Ok!!!!!\n";
	this_thread::sleep_for(chrono::seconds(5)); // Задерка 5 сек
	thread t2(ClientThread, "FghghhhMyClient");
	cout << "Thread2 Start Ok!!!!!\n";
	cin.get(); // Ждем нажатия Enter
	flag = false; // завершение потоки
	t1.join();
	t2.join();
	cout << "Client is end!\n";
	::system("pause");

}


text:
//
// Copyright (c) 2016-2020 Kris Jusiak (kris at jusiak dot net)
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/sml.hpp>
#include <deque>
#include <iostream>
#include <queue>
#include <string>

namespace sml = boost::sml;

struct e1 {};
struct e2 {};
struct e3 {};

const auto s1 = sml::state<class s1>;
const auto s2 = sml::state<class s2>;
const auto s3 = sml::state<class s3>;
const auto s4 = sml::state<class s4>;
const auto s5 = sml::state<class s5>;
const auto s6 = sml::state<class s6>;
const auto s7 = sml::state<class s7>;

test mix_process_n_defer_at_init = [] {
  struct c {
    auto operator()() {
      using namespace sml;
      // clang-format off
      return make_transition_table(
        * s1 + on_entry<sml::initial> / process(e1{})
        , s1 + event<e1> / defer = s2
        , s2 / defer = s3
        , s3 + event<e1> / process(e2{})
        , s3 + event<e2> / defer = s4
        , s4 + event<e2> = s5
        , s5 = s6
        , s6 + on_entry<_> / process(e3{})
        , s6 + event<e3> = s7
        , s7 = X
      );
      // clang-format on
    }
  };

  sml::sm<c, sml::process_queue<std::queue>, sml::defer_queue<std::deque>> sm{};
  expect(sm.is(sml::X));
};

test mix_process_n_defer = [] {
  struct c {
    auto operator()() {
      using namespace sml;
      // clang-format off
      return make_transition_table(
        * s1 + event<e1> / defer = s2
        , s2 / defer = s3
        , s3 + event<e1> / process(e2{})
        , s3 + event<e2> / defer = s4
        , s4 + event<e2> = s5
        , s5 = s6
        , s6 + on_entry<_> / process(e3{})
        , s6 + event<e3> = s7
        , s7 = X
      );
      // clang-format on
    }
  };  // internal, defer, process, defer, internal, process, internal
  sml::sm<c, sml::process_queue<std::queue>, sml::defer_queue<std::deque>> sm{};
  sm.process_event(e1{});
  expect(sm.is(sml::X));
};

test process_n_defer_again = [] {
  struct sub {
    auto operator()() {
      using namespace sml;
      // clang-format off
      return make_transition_table(
        * s2 + event<e1> / defer
        , s2 + event<e3> / defer
        , s2 + event<e2> = s3
        , s3 + on_entry<_> / [](std::string & calls){calls+="|s3_entry";}
        , s3 + event<e1> / [](std::string & calls){calls+="|e1";}
      );
      // clang-format on
    }
  };

  struct c {
    auto operator()() {
      using namespace sml;
      // clang-format off
      return make_transition_table(
        * s1 = state<sub>
        // Check that deferred events are only propagated inside sub state machine.
        , state<sub> + event<e3> / [](std::string & calls){calls+="|e3";}
      );
      // clang-format on
    }
  };

  std::string calls;
  sml::sm<c, sml::process_queue<std::queue>, sml::defer_queue<std::deque>> sm{calls};
  sm.process_event(e1{});
  sm.process_event(e1{});
  sm.process_event(e1{});
  sm.process_event(e3{});
  expect(calls == "");
  sm.process_event(e2{});
  std::cout << calls << "\n";
  expect(calls == "|s3_entry|e1|e1|e1");
};

max_stars_repo_name: seigtm/sml

max_issues_repo_name: seigtm/sml

max_forks_repo_name: seigtm/sml


text:
// Copyright 2013-2017 Antony Polukhin

// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

#include <boost/lexical_cast.hpp>
#include <string>
#include <cstdio>

#ifdef BOOST_MSVC
#  pragma warning(disable: 4996) // `strerror` is not safe
#endif

//[lexical_cast_log_errno
//`The following example uses numeric data in a string expression:

void log_message(const std::string &);

void log_errno(int yoko)
{
    log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
}

//] [/lexical_cast_log_errno]

//[lexical_cast_fixed_buffer
//`The following example converts some number and puts it to file:

void number_to_file(int number, FILE* file)
{
    typedef boost::array<char, 50> buf_t; // You can use std::array if your compiler supports it
    buf_t buffer = boost::lexical_cast<buf_t>(number); // No dynamic memory allocation
    std::fputs(buffer.begin(), file);
}

//] [/lexical_cast_fixed_buffer]

//[lexical_cast_substring_conversion
//`The following example takes part of the string and converts it to `int`:

int convert_strings_part(const std::string& s, std::size_t pos, std::size_t n)
{
    return boost::lexical_cast<int>(s.data() + pos, n);
}

//] [/lexical_cast_substring_conversion]

void log_message(const std::string &) {}

int main()
{
    return 0;
}


text:
// For conditions of distribution and use, see copyright notice in license.txt

#include "DebugOperatorNew.h"

#include <boost/thread.hpp>

#include "MemoryLeakCheck.h"

#include "Foundation.h"
#include "ModuleManager.h"

#include "HttpUtilities.h"

#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
// for reporting memory leaks upon debug exit
#include <crtdbg.h>
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
// For generating minidump
#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>
#pragma warning(push)
#pragma warning(disable : 4996)
#include <strsafe.h>
#pragma warning(pop)
#endif

void setup(Foundation::Framework &fw);
int run(int argc, char **argv);
void options(int argc, char **argv, Foundation::Framework &fw);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generate_dump(EXCEPTION_POINTERS* pExceptionPointers);
#endif

int main (int argc, char **argv)
{
    int return_value = EXIT_SUCCESS;

    // set up a debug flag for memory leaks. Output the results to file when the app exits.
    // Note that this file is written to the same directory where the executable resides,
    // so you can only use this in a development version where you have write access to
    // that directory.
#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
    int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag(tmpDbgFlag);

    HANDLE hLogFile = CreateFileW(L"fullmemoryleaklog.txt", GENERIC_WRITE,
      FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
    __try
    {
#endif
        return_value = run(argc, argv);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
    }
    __except(generate_dump(GetExceptionInformation()))
    {
    }
#endif

#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
    if (hLogFile != INVALID_HANDLE_VALUE)
    {
       _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_WARN, hLogFile);
       _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_ERROR, hLogFile);
       _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_ASSERT, hLogFile);
    }
#endif

    // Note: We cannot close the file handle manually here. Have to let the OS close it
    // after it has printed out the list of leaks to the file.
//  CloseHandle(hLogFile);

    return return_value;
}

//! post init setup for framework
void setup (Foundation::Framework &fw)
{
}

int run (int argc, char **argv)
{
    int return_value = EXIT_SUCCESS;

    // Create application object
#if !defined(_DEBUG) || !defined (_MSC_VER)
    try
#endif
    {
        HttpUtilities::InitializeHttp();
        Foundation::Framework fw(argc, argv);
        if (fw.Initialized())
        {
            setup (fw);

            fw.Go();
        }

        HttpUtilities::UninitializeHttp();
    }
#if !defined(_DEBUG) || !defined (_MSC_VER)
    catch (std::exception& e)
    {
        Foundation::Platform::Message("An exception has occurred!", e.what());
#if defined(_DEBUG)
        throw;
#else
        return_value = EXIT_FAILURE;
#endif
    }
#endif

    return return_value;
}

#if defined(_MSC_VER) && defined(WINDOWS_APP)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    // Parse Windows command line
    std::vector<std::string> arguments;

    std::string cmdLine(lpCmdLine);
    unsigned i;
    unsigned cmdStart = 0;
    unsigned cmdEnd = 0;
    bool cmd = false;
    bool quote = false;

    arguments.push_back("viewer");

    for (i = 0; i < cmdLine.length(); ++i)
    {
        if (cmdLine[i] == '\"')
            quote = !quote;
        if ((cmdLine[i] == ' ') && (!quote))
        {
            if (cmd)
            {
                cmd = false;
                cmdEnd = i;
                arguments.push_back(cmdLine.substr(cmdStart, cmdEnd-cmdStart));
            }
        }
        else
        {
            if (!cmd)
            {
               cmd = true;
               cmdStart = i;
            }
        }
    }
    if (cmd)
        arguments.push_back(cmdLine.substr(cmdStart, i-cmdStart));

    std::vector<const char*> argv;
    for (int i = 0; i < arguments.size(); ++i)
        argv.push_back(arguments[i].c_str());

    if (argv.size())
        return main(argv.size(), (char**)&argv[0]);
    else
        return main(0, 0);
}
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generate_dump(EXCEPTION_POINTERS* pExceptionPointers)
{
    BOOL bMiniDumpSuccessful;
    WCHAR szPath[MAX_PATH];
    WCHAR szFileName[MAX_PATH];

    // Can't use Foundation::Application for application name and version,
    // since it might have not been initialized yet, or it might have caused
    // the exception in the first place
    WCHAR* szAppName = L"realXtend";
    WCHAR* szVersion = L"Naali_v0.3.1";
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;

    GetLocalTime( &stLocalTime );
    GetTempPathW( dwBufferSize, szPath );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
    CreateDirectoryW( szFileName, 0 );
    StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
               szPath, szAppName, szVersion,
               stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
               stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
               GetCurrentProcessId(), GetCurrentThreadId());

    hDumpFile = CreateFileW(szFileName, GENERIC_READ|GENERIC_WRITE,
                FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE;

    bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                    hDumpFile, MiniDumpWithDataSegs, &ExpParam, 0, 0);

    std::wstring message(L"Program ");
    message += szAppName;
    message += L" encountered an unexpected error.\n\nCrashdump was saved to location:\n";
    message += szFileName;

    if (bMiniDumpSuccessful)
        Foundation::Platform::Message(L"Minidump generated!", message);
    else
        Foundation::Platform::Message(szAppName, L"Unexpected error was encountered while generating minidump!");

    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

max_stars_repo_name: mattire/naali

max_issues_repo_name: mattire/naali

max_forks_repo_name: mattire/naali


text:
#pragma once

#include <coma/detail/core_async.hpp>
#include <coma/detail/wait_ops.hpp>

#include <boost/asio/basic_waitable_timer.hpp>

namespace coma {

template<class Executor COMA_SET_DEFAULT_IO_EXECUTOR>
class async_cond_var
{
	using clock = std::chrono::steady_clock;
	using timer = net::basic_waitable_timer<clock, net::wait_traits<clock>, Executor>;
	using default_token = typename net::default_completion_token<Executor>::type;

public:
	using executor_type = Executor;
	template<class E>
	struct rebind_executor
	{
		using other = async_cond_var<E>;
	};

	explicit async_cond_var(const executor_type& ex)
		: m_timer{ex, timer::time_point::max()}
	{
	}
	explicit async_cond_var(executor_type&& ex)
		: m_timer{std::move(ex), timer::time_point::max()}
	{
	}
	~async_cond_var() = default;
	async_cond_var(const async_cond_var&) = delete;
	async_cond_var& operator=(const async_cond_var&) = delete;

	template<class CompletionToken = default_token,
			 typename =
				 typename std::enable_if<!detail::is_predicate<CompletionToken>::value>::type>
	COMA_NODISCARD auto async_wait(CompletionToken&& token = default_token{})
		-> COMA_ASYNC_RETURN_EC
	{
		return net::async_initiate<CompletionToken, void(boost::system::error_code)>(
			detail::run_wait_op{}, token, &m_timer);
	}

	template<class Predicate, class CompletionToken = default_token,
			 typename = typename std::enable_if<detail::is_predicate<Predicate>::value>::type>
	COMA_NODISCARD auto async_wait(Predicate&& pred, CompletionToken&& token = default_token{})
		-> COMA_ASYNC_RETURN_EC
	{
		return net::async_initiate<CompletionToken, void(boost::system::error_code)>(
			detail::run_wait_pred_op{}, token, &m_timer, std::forward<Predicate>(pred));
	}

	void notify_one() { m_timer.cancel_one(); }

	void notify_all() { m_timer.cancel(); }

	executor_type get_executor() { return m_timer.get_executor(); }

private:
	timer m_timer;
};

} // namespace coma

max_stars_repo_name: gummif/coma

max_issues_repo_name: gummif/coma

max_forks_repo_name: gummif/coma


text:
//---------------------------------------------------------------------------//
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
// See http://kylelutz.github.com/compute for more information.
//---------------------------------------------------------------------------//

#define BOOST_TEST_MODULE TestIota
#include <boost/test/unit_test.hpp>

#include <boost/compute/system.hpp>
#include <boost/compute/context.hpp>
#include <boost/compute/algorithm/iota.hpp>
#include <boost/compute/container/vector.hpp>
#include <boost/compute/iterator/permutation_iterator.hpp>

#include "check_macros.hpp"
#include "context_setup.hpp"

namespace bc = boost::compute;

BOOST_AUTO_TEST_CASE(iota_int)
{
    bc::vector<int> vector(4);
    bc::iota(vector.begin(), vector.end(), 0);
    CHECK_RANGE_EQUAL(int, 4, vector, (0, 1, 2, 3));

    bc::iota(vector.begin(), vector.end(), 10);
    CHECK_RANGE_EQUAL(int, 4, vector, (10, 11, 12, 13));

    bc::iota(vector.begin() + 2, vector.end(), -5);
    CHECK_RANGE_EQUAL(int, 4, vector, (10, 11, -5, -4));

    bc::iota(vector.begin(), vector.end() - 2, 4);
    CHECK_RANGE_EQUAL(int, 4, vector, (4, 5, -5, -4));
}

BOOST_AUTO_TEST_CASE(iota_doctest)
{
    boost::compute::vector<int> vec(3, context);

//! [iota]
boost::compute::iota(vec.begin(), vec.end(), 0, queue);
//! [iota]

    CHECK_RANGE_EQUAL(int, 3, vec, (0, 1, 2));
}

BOOST_AUTO_TEST_CASE(iota_permutation_iterator)
{
    bc::vector<int> output(5);
    bc::fill(output.begin(), output.end(), 0);

    int map_data[] = { 2, 0, 1, 4, 3 };
    bc::vector<int> map(map_data, map_data + 5);

    bc::iota(bc::make_permutation_iterator(output.begin(), map.begin()),
             bc::make_permutation_iterator(output.end(), map.end()),
             1);
    CHECK_RANGE_EQUAL(int, 5, output, (2, 3, 1, 5, 4));
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: bastiankoe/compute

max_issues_repo_name: bastiankoe/compute

max_forks_repo_name: bastiankoe/compute


text:
#pragma once

#include <cstdint>
#include <cstdio>
#include <cstring>
#include <string>
#include <experimental/source_location>

#include <boost/format.hpp>
#include <boost/json.hpp>

#include "../util/asjson.hpp"
#include "../util/jsontype.hpp"

namespace ts7 {
  namespace jsonrpc {
    namespace error {
      /**
       * @brief List of errors
       *
       * List of errors that can occur within the library.
       *
       * @note Everything within the library uses std::int32_t, so that it
       * is extendable by applications.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      enum class ErrorCodes : std::int32_t {
        /// Parsing the jsonrpc failed
        PARSE_ERROR = -32700,

        /// The request is invalid, this can contain sub reasons
        INVALID_REQUEST = -32600,

        /// Method is not registered / known
        METHOD_NOT_FOUND = -32601,

        /// Used whenever an invalid parameter was found, can contain sub reasons
        INVALID_PARAMS = -32602,

        /// Any internal error
        INTERNAL_ERROR = -32603,

        /// Unknown error
        UNKNOWN_ERROR = 0,

        /// Field jsonrpc is not present
        JSONRPC_MISSING = 1,

        /// Field jsonrpc is not a string, but exists
        JSONRPC_NOT_A_STRING,

        /// Field jsonrpc contains any value unequal to "2.0"
        JSONRPC_UNKNOWN_SPECIFICATION,

        /// Field method is not present
        METHOD_MISSING,

        /// Field method is not a string, but exists
        METHOD_NOT_A_STRING,

        /// Field id is not present
        ID_MISSING,

        /// Field id has a type that differs from the expected one
        ID_WRONG_TYPE,

        /// Field params is not present
        PARAMS_MISSING,

        /// Field params is not an object, but exists
        PARAMS_NOT_AN_OBJECT,

        /// A parameter is not present
        PARAMETER_MISSING,

        /// A parameter exists, but is has an unexpected type
        PARAMETER_WRONG_TYPE,

        /// A parameter value is missing
        PARAMETER_VALUE_MISSING,

        /// Field error is missing
        ERROR_MISSING,

        /// Field error is not an object
        ERROR_NOT_AN_OBJECT,

        /// Field code within error is missing
        ERROR_CODE_MISSING,

        /// FIeld code within error is not a number
        ERROR_CODE_NOT_A_NUMBER,

        /// Field message within error is missing
        ERROR_MESSAGE_MISSING,

        /// Field message within error is not a string
        ERROR_MESSAGE_NOT_A_STRING,

        /// There was no callback stored in the error handler
        ERROR_CALLBACK_MISSING,

        /// Field result is missing
        RESULT_MISSING,

        /// Field result has the wrong type
        RESULT_WRONG_TYPE,

        /// This procedure needs to be implemented
        NOT_YET_IMPLEMENTED,
      };

      /// Conversion from ErrorCode to std::int32_t
      inline constexpr std::int32_t Code(ErrorCodes code) {
        return static_cast<std::int32_t>(code);
      }

      /**
       * @brief Error code
       *
       * Represents everything that is required to create a JSON-RPC error
       * message. This includes the code, the message and any additional data.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      class ErrorCode {
        public:
          /**
           * @brief constructor
           *
           * Default constructor which should never be used. Required to exist
           * for \p util::maybe_failed.
           *
           * @note This should be the only way to create an \p ErrorCodes::UNKNOWN_ERROR.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          inline ErrorCode()
            : code(static_cast<std::int32_t>(ErrorCodes::UNKNOWN_ERROR)),
              message("Unknown error")
          {}

          /**
           * @brief constructor
           *
           * Creates an error with the provided error code as well as the message.
           *
           * @param code The error code that shall be provided.
           * @param message The corresponding message to the error code.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          inline ErrorCode(std::int32_t code, std::string&& message)
            : code(code),
              message(std::move(message))
          {}

          /**
           * @brief constructor
           *
           * Creates an error with code, message and a JSON object that
           * shall be provided as data field.
           *
           * @param code The error code.
           * @param message The corresponding message to the error code.
           * @param data Additional data that shall be provided with the error.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          inline ErrorCode(std::int32_t code, std::string&& message, const boost::json::value& data)
            : code(code),
              message(std::move(message)),
              data(data)
          {}

          /**
           * @brief constructor
           *
           * Creates an error with a code and the corresponding
           * message. Additional data can be added as pairs of key and value.
           *
           * @note The parameter args needs to be a list of two always. The key
           * always needs to be a string and the value can be any type as long
           * as it can be converted to a JSON value by \p util::AsJson.
           *
           * @tparam TArgs List of parameter data types.
           *
           * @param code The error of the error.
           * @param message The corresponding error message.
           * @param args List of keys and values to be stored as additional data.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          template <typename... TArgs>
          inline ErrorCode(std::int32_t code, std::string&& message, TArgs... args)
            : code(code),
              message(std::move(message))
          {
            boost::json::object dataObject;
            apply_args(dataObject, args...);

            data = dataObject;
          }

          void addData(const std::string& field, const boost::json::value& value) {
            if (!data.is_object()) {
              data = boost::json::object();
            }

            boost::json::object& d = data.as_object();
            d[field] = value;
          }

          /**
           * @brief Convert to JSON object
           *
           * Converts the \p ErrorCode object to a JSON object.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          inline operator boost::json::object() const {
            boost::json::object o;
            o["code"] = code;
            o["message"] = message;

            if (!data.is_null()) {
              o["data"] = data;
            }

            return o;
          }

          inline std::int32_t getCode() const {
            return code;
          }

          inline const std::string& getMessage() const {
            return message;
          }

          /// Error code cast operator
          inline operator std::int32_t() const {
            return code;
          }

          /// Error message cast operator
          inline operator const std::string&() const {
            return message;
          }

          /**
           * @brief Missing field
           *
           * Factory method to create a missing field \p ErrorCode.
           *
           * @note This adds the fieldnam as additional information to the \p ErrorCode object.
           *
           * @param code The error code that needs to be stored.
           * @param field The name of the field that is missing.
           * @param format The format specifier for the error message.
           *
           * @return Returns the created \p ErrorCode.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          static inline ErrorCode MissingField(std::int32_t code, const std::string& field, const std::string& format = "Missing field \"%1%\"") {
            return ErrorCode(code, (boost::format(format) % field).str(), "name", field);
          }

          /**
           * @brief Wrong type
           *
           * Factory method to create an \p ErrorCode, if a field or
           * parameter has an unexpected data type.
           *
           * @note Adds the fieldname, its actual data type and the expected
           * data type as additional information to the \p ErrorCode.
           *
           * @param code The error code.
           * @param field The name of the field or parameter.
           * @param actual The actual data type of the field.
           * @param expected The expected data type of the field.
           * @param format The format specifier to generate the error message.
           *
           * @return Returns the created \p ErrorCode.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          static inline ErrorCode WrongType(std::int32_t code, const std::string& field, util::JsonType actual, util::JsonType expected, const std::string& format = "Field \"%1%\" is of type \"%2%\", expected \"%3%\"") {
            return ErrorCode(
              code,
              (boost::format(format) % field % GetJsonTypeName(actual) % GetJsonTypeName(expected)).str(),
              "name", field,
              "actual", GetJsonTypeName(actual),
              "expected", GetJsonTypeName(expected)
            );
          }

          /**
           * @brief Missing parameter
           *
           * Creates an \p ErrorCode, whenever a parameter is missing.
           *
           * @note This calls internally \p MissingField factory method.
           *
           * @param code The provided error code.
           * @param field The name of the parameter, that is missing.
           *
           * @return Returns the created \p ErrorCode.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          static inline ErrorCode MissingParameter(std::int32_t code, const std::string& field) {
            return MissingField(code, field, "Missing parameter \"%1%\"");
          }

          /**
           * @brief Wrong parameter type
           *
           * Factory method to create an \p ErrorCode object, whenever an
           * unexpected parameter type is found.
           *
           * @note This adds the fieldname, its actual data type and the
           * expected data type as additional information. This calls
           * internally \p WrongType.
           *
           * @param code The error code provided.
           * @param field The parameter name.
           * @param actual Its actual data type.
           * @param expected The expected data type.
           *
           * @return Returns the created \p ErrorCode object.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          static inline ErrorCode WrongParameterType(std::int32_t code, const std::string& field, util::JsonType actual, util::JsonType expected) {
            return WrongType(code, field, actual, expected, "Parameter \"%1%\" is of type \"%2%\", expected \"%3%\"");
          }

        protected:
          /// The error code
          std::int32_t code;

          /// The error message
          std::string message;

          /// Additional information. Those are optional and can be omitted.
          boost::json::value data;

          /**
           * @brief Apply json entry
           *
           * Adds additional information to the JSON object.
           *
           * @note This function is only called for the very last key value pair.
           *
           * @tparam TData The data type that shall be added.
           *
           * @param o The JSON object that shall be extended by the additional information.
           * @param name The key of the entry.
           * @param value The value that shall be added.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          template <typename TData>
          inline void apply(boost::json::object& o, const std::string& name, const TData& value) {
            o[name] = util::AsJson<TData>(value);
          }

          /**
           * @brief Apply json entry
           *
           * Adds additional information to the JSON object.
           *
           * @note This function is  called for every key value pair, except the very last one.
           *
           * @tparam TData The data type that shall be added.
           * @tparam TArgs The list of key value pairs that shall be added.
           *
           * @param o The JSON object that shall be extended by the additional information.
           * @param name The key of the entry.
           * @param value The value that shall be added.
           * @param agrs The list of remaining key value pairs that shall be added.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          template <typename TData, typename... TArgs>
          inline void apply(boost::json::object& o, const std::string& name, const TData& value, TArgs... args) {
            o[name] = value;
            apply(o, args...);
          }

          /**
           * @brief Apply json entries
           *
           * Adds additional information to the JSON object.
           *
           * @tparam TArgs The list of key value pairs that shall be added.
           *
           * @param o The JSON object that shall be extended by the additional information.
           * @param agrs The list of key value pairs that shall be added.
           *
           * @since 1.0
           *
           * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
           */
          template <typename... TArgs>
          inline void apply_args(boost::json::object& o, TArgs... args) {
            apply(o, args...);
          }
      };

      /**
       * @brief Parse error
       *
       * Factory method to create a parse error.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ParseError() {
        return ErrorCode(Code(ErrorCodes::PARSE_ERROR), "Parse error");
      }

      /**
       * @brief Invalid request
       *
       * Factory method to create an invalid request error. This always contains another
       * error that made the request invalid.
       *
       * @param data The \p ErrorCode that triggered the invalid request.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode InvalidRequest(const ErrorCode& data) {
        const boost::json::object o = data;
        return ErrorCode(Code(ErrorCodes::INVALID_REQUEST), "Invalid request", boost::json::value(o));
      }

      /**
       * @brief Method not found
       *
       * Factroy method to create an error, if the requested method is not
       * exposed to the server/client.
       *
       * @param name Name of the method that could not be found.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode MethodNotFound(const std::string& name) {
        return ErrorCode(Code(ErrorCodes::METHOD_NOT_FOUND), (boost::format("Method \"%1%\" not found") % name).str(), "method", name);
      }

      /**
       * @brief Invalid params
       *
       * Factory method to create an error, if at least one of the parameter
       * were invalid for any reason.
       *
       * @param data \p ErrorCode that caused the invalid params error.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode InvalidParams(const ErrorCode& data) {
        const boost::json::object o = data;
        return ErrorCode(Code(ErrorCodes::INVALID_PARAMS), "Invalid parameter", boost::json::value(o));
      }

      /**
       * @brief Internal error
       *
       * Factory method to create any internal error, whenever it has occured.
       *
       * @tparam TArgs List of key value pair types provided for additional information.
       *
       * @param args List of key value pair entries that shall be added as
       * additional information to the \p ErrorCode.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      template <typename... TArgs>
      [[maybe_unused]] static inline ErrorCode InternalError(TArgs... args) {
        return ErrorCode(Code(ErrorCodes::INTERNAL_ERROR), "Internal Error", args...);
      }

      /**
       * @brief Jsonrpc missing
       *
       * Factory method to create an error, if the jsonrpc field is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode JsonrpcMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::JSONRPC_MISSING), "jsonrpc");
      }

      /**
       * @brief Jsonrpc not a string
       *
       * Factory method that creates an \p ErrorCode, if the jsonrpc field
       * exists but has an unexpected data type that is not string.
       *
       * @param t The actual data type of the jsonrpc field.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode JsonrpcNotAString(util::JsonType t) {
        return ErrorCode::WrongType(Code(ErrorCodes::JSONRPC_NOT_A_STRING), "jsonrpc", t, util::JsonType::STRING);
      }

      /**
       * @brief Jsonrpc unknown specification
       *
       * Factory method to create an \p ErrorCode, if the jsonrpc field
       * exists and is a string, but has an unexpected value that is
       * not "2.0".
       *
       * @param value The value that got found.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode JsonrpcUnknownSpecification(const std::string& value) {
        return ErrorCode(
          Code(ErrorCodes::JSONRPC_UNKNOWN_SPECIFICATION),
          (boost::format("Unknown JSON-RPC specification \"%s\", exptected \"2.0\"") % value).str()
        );
      }

      /**
       * @brief Method missing
       *
       * Factory method to create an \p ErrorCode, if the method field
       * is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode MethodMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::METHOD_MISSING), "method");
      }

      /**
       * @brief Method not a string
       *
       * Factory method to create an \p ErrorCode, if the the method field
       * exists but is not a string.
       *
       * @param t The actual data type of the method field.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode MethodNotAString(util::JsonType t) {
        return ErrorCode::WrongType(Code(ErrorCodes::METHOD_NOT_A_STRING), "method", t, util::JsonType::STRING);
      }

      /**
       * @brief ID missing
       *
       * Factory method to create an \p ErrorCode, if the id field is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode IdMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::ID_MISSING), "id");
      }

      /**
       * @brief ID wrong type
       *
       * Factory method to create an \p ErrorCode, if the id field
       * exists, but has an unexpected data type.
       *
       * @tparam TId Expected data type of the id field.
       *
       * @param t Actual data type of the found id field.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      template <typename TId>
      [[maybe_unused]] static inline ErrorCode IdWrongType(util::JsonType t) {
        return ErrorCode::WrongType(Code(ErrorCodes::ID_WRONG_TYPE), "id", t, util::AsJson<TId>::type);
      }

      /**
       * @brief Params missing
       *
       * Factory method to create an \p ErrorCode, if the the params
       * field is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ParamsMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::PARAMS_MISSING), "params");
      }

      /**
       * @brief Params not an object
       *
       * Factory method to create an \p ErrorCode, if the params object is
       * not an object.
       *
       * @param t The actual data type of the params field.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ParamsNotAnObject(util::JsonType t) {
        return ErrorCode::WrongType(Code(ErrorCodes::PARAMS_NOT_AN_OBJECT), "params", t, util::JsonType::OBJECT);
      }

      /**
       * @brief Parameter missing
       *
       * Factory method to create an \p ErrorCode, if at least one parameter
       * is mising.
       *
       * @param name The name of the parameter that is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ParameterMissing(const std::string& name) {
        return ErrorCode::MissingParameter(Code(ErrorCodes::PARAMETER_MISSING), name);
      }

      /**
       * @brief Parameter wrong type
       *
       * Factory method to create an \p ErrorCode, if the desired parameter
       * exists, but has an unexpected data type.
       *
       * @param name The name of the parameter.
       * @param actual The parameters actual data type.
       * @param expected The expected data type of the parameter.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ParameterWrongType(const std::string& name, util::JsonType actual, util::JsonType expected) {
        return ErrorCode::WrongParameterType(Code(ErrorCodes::PARAMETER_WRONG_TYPE), name, actual, expected);
      }

      /**
       * @brief Parameter value missing
       *
       * Factory method to create an \p ErrorCode, if the there was no value
       * and no default value provided for a parameter.
       *
       * @param name The name of the parameter.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ParameterValueuMissing(const std::string& name) {
        return ErrorCode(Code(ErrorCodes::PARAMETER_VALUE_MISSING), (boost::format("No value or default value provided for parameter \"%1%\"") % name).str());
      }

      /**
       * @brief Error missing
       *
       * Factory method to create an \p ErrorCode, if the error field is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ErrorMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::ERROR_MISSING), "error");
      }

      /**
       * @brief Error not an object
       *
       * Factory method to create an \p ErrorCode, if the the error field
       * exists but is not an object.
       *
       * @param t The actual data type of the error field.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ErrorNotAnObject(util::JsonType t) {
        return ErrorCode::WrongType(Code(ErrorCodes::ERROR_NOT_AN_OBJECT), "error", t, util::JsonType::OBJECT);
      }

      /**
       * @brief Error code missing
       *
       * Factory method to create an \p ErrorCode, if the code field within
       * the error object does not exist.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ErrorCodeMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::ERROR_CODE_MISSING), "code");
      }

      /**
       * @brief Error code not a number
       *
       * Factory method to create an \p ErrorCode, if the code field
       * within the error object is not a number.
       *
       * @param t The actual data type of the error code.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ErrorCodeNotANumber(util::JsonType t) {
        return ErrorCode::WrongType(Code(ErrorCodes::ERROR_CODE_NOT_A_NUMBER), "code", t, util::JsonType::NUMBER);
      }

      /**
       * @brief Error message missing
       *
       * Factory method to create an \p ErrorCode, if the message field wihin
       * the error object is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ErrorMessageMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::ERROR_MESSAGE_MISSING), "message");
      }

      /**
       * @brief Error message not a string
       *
       * Factory method to create an \p ErrorCode, if the message field
       * within the error object exists but is not a string.
       *
       * @param t The actual data type of the message field.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ErrorMessageNotAString(util::JsonType t) {
        return ErrorCode::WrongType(Code(ErrorCodes::ERROR_MESSAGE_NOT_A_STRING), "message", t, util::JsonType::STRING);
      }

      /**
       * @brief Error callback missing
       *
       * Factory method to create an \p ErrorCode, if there is no callback
       * provided for the error handler.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ErrorCallbackMissing() {
        return ErrorCode(Code(ErrorCodes::ERROR_CALLBACK_MISSING), "Error callback missing");
      }

      /**
       * @brief Result missing
       *
       * Factory method to create an \p ErrorCode, if the result field
       * is missing.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ResultMissing() {
        return ErrorCode::MissingField(Code(ErrorCodes::RESULT_MISSING), "result");
      }

      [[maybe_unused]] static inline ErrorCode NotYetImplemented() {
        return ErrorCode(Code(ErrorCodes::NOT_YET_IMPLEMENTED), "Not Yet Implemented");
      }

      /**
       * @brief Result wrong type
       *
       * Factory method to create an \p ErrorCode, if the result field
       * exists but has an unexpected data type.
       *
       * @param actual The actual data type of the result field.
       * @param expected The expected data type of the result field.
       *
       * @return Returns the created \p ErrorCode.
       *
       * @since 1.0
       *
       * @author Tarek Schwarzinger <tarek.schwarzinger@googlemail.com>
       */
      [[maybe_unused]] static inline ErrorCode ResultWrongType(util::JsonType actual, util::JsonType expected = util::JsonType::OBJECT) {
        return ErrorCode::WrongType(Code(ErrorCodes::RESULT_WRONG_TYPE), "result", actual, expected);
      }

      struct Exception : public std::runtime_error {
        using source_location = std::experimental::source_location;

        inline Exception(const ErrorCode& ec, const source_location& location = source_location::current())
          : std::runtime_error(ec),
            ec(ec.getCode(), std::string(ec.getMessage()), "location", location)
        {}

        inline Exception(std::int32_t code, std::string&& message, const source_location& location = source_location::current())
          : std::runtime_error(message),
            ec(code, std::move(message), "location", location)
        {}

        inline Exception(std::int32_t code, std::string&& message, const boost::json::value& data, const source_location& location = source_location::current())
          : std::runtime_error(message),
            ec(code, std::move(message), data)
        {
          ec.addData("location", util::AsJson<source_location>(location));
        }

        template <typename... TArgs>
        inline Exception(std::int32_t code, std::string&& message, const source_location& location, TArgs... args)
          : std::runtime_error(message),
            ec(code, std::move(message), "location", location, args...)
        {}

        template <typename... TArgs>
        inline Exception(std::int32_t code, std::string&& message, TArgs... args)
          : std::runtime_error(message),
            ec(code, std::move(message), args...)
        {}

        inline operator boost::json::object() const {
          return ec;
        }

        ErrorCode ec;
      };
    }
  }
}


text:
#include <boost/parameter.hpp>

BOOST_PARAMETER_NAME((pass_foo, keywords) foo)

BOOST_PARAMETER_FUNCTION(
    (int), f, keywords, (required (foo, *))
)
{
    return foo + 1;
}

#include <boost/core/lightweight_test.hpp>

int main()
{
    int x = f(pass_foo = 41);
    BOOST_TEST_EQ(x, 42);
    return boost::report_errors();
}


text:
// Copyright (c) 2021 Bitcoin Association
// Distributed under the Open BSV software license, see the accompanying file
// LICENSE.

#include "double_spend/dsdetected_message.h"

#include "config.h"
#include "merkleproof.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "uint256.h"
#include <algorithm>
#include <boost/functional/hash.hpp>
#include <iterator>
#include <stdexcept>

using namespace std;

// Comparison operator for DSDetected
bool operator==(const DSDetected& a, const DSDetected& b)
{
    return a.GetVersion() == b.GetVersion() &&
           a.mBlockList == b.mBlockList;
}

// Comparison operator for DSDetected::BlockDetails
bool operator==(const DSDetected::BlockDetails& a,
                const DSDetected::BlockDetails& b)
{
    return a.mBlockHeaders == b.mBlockHeaders &&
           a.mMerkleProof == b.mMerkleProof;
}

size_t hash_value(const CBlockHeader& header)
{
    size_t seed{0};
    boost::hash_combine(seed, header.nVersion);
    boost::hash_combine(seed, header.hashPrevBlock);
    boost::hash_combine(seed, header.hashPrevBlock);
    boost::hash_combine(seed, header.nTime);
    boost::hash_combine(seed, header.nBits);
    boost::hash_combine(seed, header.nNonce);
    return seed;
}

size_t hash_value(const DSDetected::BlockDetails& blocks)
{
    size_t seed{0};
    boost::hash_range(seed, blocks.mBlockHeaders.begin(), blocks.mBlockHeaders.end());
    boost::hash_combine(seed, blocks.mMerkleProof);
    return seed;
}

namespace std
{
    size_t hash<DSDetected>::operator()(const DSDetected& ds) const
    {
        size_t seed{0};
        boost::hash_combine(seed, ds.GetVersion());
        boost::hash_range(seed, ds.begin(), ds.end());
        return seed;
    };
}

std::size_t sort_hasher(const DSDetected& ds)
{
    size_t seed{0};
    boost::hash_combine(seed, ds.GetVersion());

    vector<size_t> hashes(ds.size());
    std::transform(ds.begin(),
                   ds.end(),
                   hashes.begin(),
                   [](const auto& fork) { return hash_value(fork); });

    sort(hashes.begin(), hashes.end());
    boost::hash_range(seed, hashes.begin(), hashes.end());

    return seed;
}

void DSDetected::BlockDetails::Validate(const MerkleProof& mp)
{
    if(mp.Flags() != 5)
        throw runtime_error("Unsupported DSDetected merkle proof flags");

    if(mp.Index() == 0)
        throw runtime_error("Unsupported DSDetected merkle proof index");

    if(any_of(mp.begin(), mp.end(), [](const auto& node) {
           return node.mType != 0;
       }))
        throw runtime_error("Unsupported DSDetected merkle proof type");
}

// Convert to JSON suitable for sending to a remote webhoo
UniValue DSDetected::ToJSON(const Config& config) const
{
    UniValue document{UniValue::VOBJ};

    document.push_back(Pair("version", mVersion));

    UniValue blocks{UniValue::VARR};
    for(const auto& block : mBlockList)
    {
        UniValue blockJson{UniValue::VOBJ};

        if(!block.mBlockHeaders.empty())
        {
            blockJson.push_back(
                Pair("divergentBlockHash",
                     block.mBlockHeaders.back().GetHash().ToString()));
        }

        UniValue headers{UniValue::VARR};
        for(const auto& header : block.mBlockHeaders)
        {
            UniValue headerJson{UniValue::VOBJ};
            headerJson.push_back(Pair("version", header.nVersion));
            headerJson.push_back(
                Pair("hashPrevBlock", header.hashPrevBlock.ToString()));
            headerJson.push_back(
                Pair("hashMerkleRoot", header.hashMerkleRoot.ToString()));
            headerJson.push_back(
                Pair("time", static_cast<uint64_t>(header.nTime)));
            headerJson.push_back(
                Pair("bits", static_cast<uint64_t>(header.nBits)));
            headerJson.push_back(
                Pair("nonce", static_cast<uint64_t>(header.nNonce)));
            headers.push_back(headerJson);
        }
        blockJson.push_back(Pair("headers", headers));

        blockJson.push_back(
            Pair("merkleProof",
                 block.mMerkleProof.ToJSON(
                     config.GetDoubleSpendDetectedWebhookMaxTxnSize())));

        blocks.push_back(blockJson);
    }
    document.push_back(Pair("blocks", blocks));

    return document;
}

bool IsValid(const DSDetected::BlockDetails& fork)
{
    if(fork.mBlockHeaders.empty())
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message: no block headers\n");
        return false;
    }

    if(!contains_tx(fork.mMerkleProof))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message: doesn't contain "
                 "Transaction\n");
        return false;
    }

    if(contains_coinbase_tx(fork.mMerkleProof))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message: contains coinbase"
                 " transaction\n");
        return false;
    }

    if(!contains_merkle_root(fork.mMerkleProof))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message: doesn't contain "
                 "merkle root\n");
        return false;
    }

    if(!FormsChain(fork.mBlockHeaders))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message: block_headers do not "
                 "form a chain\n");
        return false;
    }

    if(ContainsDuplicateHeaders(fork.mBlockHeaders))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message: contains duplicate headers\n");
        return false;

    }

    if(!fork.mMerkleProof.Verify())
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message: merkle proof is invalid\n");
        return false;
    }

    return true;
}

bool ValidateForkCount(const DSDetected& msg)
{
    return msg.size() >= 2;
}

bool ValidateCommonAncestor(const DSDetected& msg)
{
    // Check all forks have the same common ancestor
    return adjacent_find(msg.begin(),
                         msg.end(),
                         [](const auto& fork1, const auto& fork2) {
                             assert(!fork1.mBlockHeaders.empty());
                             assert(!fork2.mBlockHeaders.empty());
                             return fork1.mBlockHeaders.back().hashPrevBlock !=
                                    fork2.mBlockHeaders.back().hashPrevBlock;
                         }) == msg.end();
}

bool ValidateDoubleSpends(const DSDetected& msg)
{
    // Gather all the spent Outpoints and their fork index in the msg
    int index{0};
    using index_outpoint = pair<int, COutPoint>;
    vector<index_outpoint> indexed_ops;
    for(const auto& fork : msg)
    {
        const CTransaction* tx{fork.mMerkleProof.Tx()};
        for(const auto& ip : tx->vin)
            indexed_ops.push_back({index, ip.prevout});
        ++index;
    }

    // sort by the outpoints, ignoring the index
    const auto outpoint_less = [](const auto& a, const auto& b) {
        return a.second < b.second;
    };
    sort(indexed_ops.begin(), indexed_ops.end(), outpoint_less);

    // Find the indices of all the duplicates - these are double-spends
    vector<uint32_t> indices;
    for(auto it{indexed_ops.begin()}; it != indexed_ops.end();)
    {
        auto r = equal_range(it, indexed_ops.end(), *it, outpoint_less);
        if(r.first != indexed_ops.end())
        {
            if(distance(r.first, r.second) > 1)
            {
                for(; r.first != r.second; ++r.first)
                    indices.push_back((*r.first).first);
            }
        }
        it = r.second;
    }

    // There must be a double spend for each fork in the msg
    if(indices.size() < msg.size())
        return false;

    // Check that each index is contained in the duplicates collection
    sort(indices.begin(), indices.end());
    const auto end = unique(indices.begin(), indices.end());
    const size_t dist = distance(indices.begin(), end);
    return dist == msg.size();
}

// Ensure there are no duplicate transactions
bool AreTxsUnique(const DSDetected& msg)
{
    vector<uint256> txids(msg.size());
    transform(msg.begin(),
              msg.end(),
              txids.begin(),
              [](const DSDetected::BlockDetails& fork) {
                  return fork.mMerkleProof.Tx()->GetId();
              });
    sort(txids.begin(), txids.end());
    return adjacent_find(txids.cbegin(), txids.cend()) == txids.cend();
}

bool IsValid(const DSDetected& msg)
{
    if(!ValidateForkCount(msg))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message - invalid fork "
                 "count\n");
        return false;
    }

    if(!all_of(msg.begin(),
               msg.end(),
               [](const DSDetected::BlockDetails& fork) {
                   return IsValid(fork);
               }))
        return false;

    if(!ValidateCommonAncestor(msg))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message - invalid common "
                 "ancestor\n");
        return false;
    }

    if(!AreTxsUnique(msg))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message - duplicate txids in "
                 "merkle proofs\n");
        return false;
    }

    // Verify all forks have a tx that double-spends a COutPoint with at least
    // one other fork in the message.
    if(!ValidateDoubleSpends(msg))
    {
        LogPrint(BCLog::NETMSG,
                 "Invalid double-spend detected message - no double spend "
                 "detected\n");
        return false;
    }

    return true;
}

namespace
{
    bool linked(const CBlockHeader& a, const CBlockHeader& b)
    {
        return a.hashPrevBlock == b.GetHash();
    }
}

bool FormsChain(const vector<CBlockHeader>& headers)
{
    if(headers.empty())
        return false;

    if(headers.size() == 1)
        return true;

    const auto it{mismatch(headers.begin(),
                           headers.end() - 1,
                           headers.begin() + 1,
                           headers.end(),
                           linked)};
    return it.second == headers.end();
}

bool ContainsDuplicateHeaders(const vector<CBlockHeader>& headers)
{
    vector<size_t> hashes;
    hashes.reserve(headers.size());
    transform(headers.begin(),
              headers.end(),
              back_inserter(hashes),
              [](const auto& h) { return hash_value(h); });

    sort(hashes.begin(), hashes.end());

    return adjacent_find(hashes.begin(), hashes.end()) != hashes.end();
}

const DSDetected::BlockDetails& MaxForkLength(const DSDetected& msg)
{
    assert(!msg.empty());
    return *max_element(msg.begin(), msg.end(), [](const auto& fork1, const auto& fork2)
    {
        return fork1.mBlockHeaders.size() < fork2.mBlockHeaders.size();
    });
}

max_stars_repo_name: ZacharyPainter/bitcoin-sv

max_issues_repo_name: wjxee/bitcoin-sv

max_forks_repo_name: wjxee/bitcoin-sv