text:
// Copyright (c) 2021 Graphcore Ltd. All rights reserved.
#define BOOST_TEST_MODULE unittest_irquery_optestwrapper

#include <boost/test/unit_test.hpp>
#include <boost/trompeloeil.hpp>

#include <iostream>
#include <sstream>

#include <popart/graph.hpp>
#include <popart/ir.hpp>
#include <popart/op.hpp>

#define private public
#include <testutil/irquery/irquery.hpp>
#undef private

#include <testutil/irquery/mock_testfailuretriggerer.hpp>
#include <testutil/irquery/testop.hpp>

using namespace popart;
using namespace popart::irquery;

namespace {

auto _ = trompeloeil::_;

} // namespace

BOOST_AUTO_TEST_CASE(optestwrapper_inputs_outputs) {

  Ir ir;
  auto &mainGraph       = ir.getMainGraph();
  Op::Settings settings = Op::Settings{mainGraph, "SimpleTestOp"};

  // Add "t0" to the main graph.
  TensorInfo t0Info{DataType::INT32, {}};
  int32_t t0Data[] = {5};

  // Create this graph:
  // .---------------[main graph]---------------.
  // |     [i0]              [i1]  [i2](=inputs)|
  // |      |                 |     |           |
  // |   #1 v                 |     |           |
  // |   +---------------+    |     |           |
  // |   | testOp0       |    |     |           |
  // |   +---------------+    |     |           |
  // |   #1 |                 |     |           |
  // |      |                 |     |           |
  // |    [tmp0] .------------'     |           |
  // |      |    |                  |           |
  // |   #1 v #2 v                  |           |
  // |   +---------------+          |           |
  // |   | testOp1       |          |           |
  // |   +---------------+          |           |
  // |   #1 | #2 |                  |           |
  // |      |    |                  |           |
  // |   [tmp1][tmp2] .-------------'           |
  // |      |    |    |                         |
  // |      |    |    |                         |
  // |   #1 v #2 v #3 v                         |
  // |   +---------------+                      |
  // |   | testOp2       |                      |
  // |   +---------------+                      |
  // |   #1 | #2 | #3 |                         |
  // |      |    |    |                         |
  // |      v    v    v                         |
  // |     [o0] [o1] [o2]             (=outputs)|
  // '------------------------------------------'

  // Add inputs.
  mainGraph.getTensors().addVarInit("i0", t0Info, static_cast<void *>(&t0Data));
  mainGraph.getTensors().addVarInit("i1", t0Info, static_cast<void *>(&t0Data));
  mainGraph.getTensors().addVarInit("i2", t0Info, static_cast<void *>(&t0Data));

  // Add SimpleTestOps.
  auto testOp0 = mainGraph.createOp<TestOp>(settings);
  auto testOp1 = mainGraph.createOp<TestOp>(settings);
  auto testOp2 = mainGraph.createOp<TestOp>(settings);

  testOp0->connectInTensor(1, "i0");
  testOp0->createAndConnectOutTensor(1, "tmp0");
  testOp0->setup();

  testOp1->connectInTensor(1, "tmp0");
  testOp1->connectInTensor(2, "i1");
  testOp1->createAndConnectOutTensor(1, "tmp1");
  testOp1->createAndConnectOutTensor(2, "tmp2");
  testOp1->setup();

  testOp2->connectInTensor(1, "tmp1");
  testOp2->connectInTensor(2, "tmp2");
  testOp2->connectInTensor(3, "i2");
  testOp2->createAndConnectOutTensor(1, "o0");
  testOp2->createAndConnectOutTensor(2, "o1");
  testOp2->createAndConnectOutTensor(3, "o2");
  testOp2->setup();

  // Check inputs() is populated correctly for testOp1.
  OpTestWrapper<Op> testOp1Tw{ir, testOp1};
  std::cout << testOp1Tw.inputs().srcObjDescr << std::endl;
  BOOST_REQUIRE("101 (TestOps.TestOp:1)" == testOp1Tw.inputs().srcObjDescr);
  BOOST_REQUIRE("input" == testOp1Tw.inputs().mapTypeDescrSingular);
  BOOST_REQUIRE("inputs" == testOp1Tw.inputs().mapTypeDescrPlural);
  BOOST_REQUIRE(2 == testOp1Tw.inputs().unwrap().size());
  BOOST_REQUIRE(mainGraph.getTensors().get("tmp0") ==
                testOp1Tw.inputs().unwrap().at(1));
  BOOST_REQUIRE(mainGraph.getTensors().get("i1") ==
                testOp1Tw.inputs().unwrap().at(2));

  // Check outputs() is populated correctly for testOp2.
  OpTestWrapper<Op> testOp2Tw{ir, testOp2};
  BOOST_REQUIRE("102 (TestOps.TestOp:1)" == testOp2Tw.outputs().srcObjDescr);
  BOOST_REQUIRE("output" == testOp2Tw.outputs().mapTypeDescrSingular);
  BOOST_REQUIRE("outputs" == testOp2Tw.outputs().mapTypeDescrPlural);
  BOOST_REQUIRE(3 == testOp2Tw.outputs().unwrap().size());
  BOOST_REQUIRE(mainGraph.getTensors().get("o0") ==
                testOp2Tw.outputs().unwrap().at(1));
  BOOST_REQUIRE(mainGraph.getTensors().get("o1") ==
                testOp2Tw.outputs().unwrap().at(2));
  BOOST_REQUIRE(mainGraph.getTensors().get("o2") ==
                testOp2Tw.outputs().unwrap().at(3));
}


text:
#include <iostream>
#include <cassert>
#include <time.h>
#include "timer.h"
#include "Encoding.h"
#include "PolyTree.h"
#include "EncodingEnigmaBN.h"

#include <boost/program_options.hpp>
using namespace std;
using namespace boost::program_options;

void microbenchmarks(variables_map& config) {

#ifdef _DEBUG
	printf("\nRunning in DEBUG mode -- performance measurements should not be trusted!\n\n");
#endif

	string option = config["micro"].as<string>();
	int num_trials = config["trials"].as<int>();
	printf("About to run %d tests...\n", num_trials);

	Encoding* encoding = NewEncoding(config["encoding"].as<string>());
	if (encoding == NULL) { return; }
	Field* field = encoding->getSrcField();
  if (option.compare("mont-test") == 0) {
    assert(config["encoding"].as<string>().compare("enigma-bn") == 0);
    field = ((EncodingEnigmaBN*)encoding)->getMontField();

    ((EncodingEnigmaBN*)encoding)->testToFromMont(field, num_trials);
  }

	FieldEltArray* field1 = field->newEltArray(num_trials, true);
	FieldEltArray* field2 = field->newEltArray(num_trials, true);
	FieldEltArray* field32 = field->newEltArray(num_trials, true);

	EncodedEltArray* lencodings = encoding->new_elt_array(L, num_trials, true);
	EncodedEltArray* rencodings = encoding->new_elt_array(R, num_trials, true);
	EncodedEltArray* lencodings2 = encoding->new_elt_array(L, num_trials, true);
	EncodedEltArray* rencodings2 = encoding->new_elt_array(R, num_trials, true);
	EncodedProduct** prods = new EncodedProduct*[num_trials];

	FieldElt *fieldg1 = field->newElt(), *fieldg0 = field->newElt();
	// I'll assume 5^i are unique values, for i in [0,num_trials)
	field->set(fieldg1, 5);
	field->set(fieldg0, 1);
	for (int i = 0; i < num_trials; i++) {
		field->assignRandomElt(field1->elt(i));
		field->assignRandomElt(field2->elt(i));
		field->assignRandomElt(field32->elt(i));

    field->truncate(field1->elt(i), 254);
    field->truncate(field2->elt(i), 254);
		field->truncate(field32->elt(i), 32);

		prods[i] = encoding->new_prod();
	}

	Timer* total = timers.newTimer("Total", NULL);
	total->start();

	/////////////// Field ops ///////////////////////////
  if (option.compare("all") == 0 || option.compare("field") == 0 || option.compare("mont-test") == 0) {
		TIMEREP(field->add(field1->elt(i), field2->elt(i), field1->elt(i)), num_trials, "FieldAdd", "Total");
		TIMEREP(field->sub(field1->elt(i), field2->elt(i), field1->elt(i)), num_trials, "FieldSub", "Total");
		TIMEREP(field->mul(field1->elt(i), field2->elt(i), field1->elt(i)), num_trials, "FieldMul", "Total");
		TIMEREP(field->mul(field1->elt(i), field2->elt(i), field1->elt(i)), num_trials, "FieldDiv", "Total");

		printf("Finished field ops\n");  fflush(stdout);
	}

	/////////////// Encoding ops ///////////////////////////
	if (option.compare("all") == 0 || option.compare("encoding") == 0) {
		TIMEREP(encoding->encode(L, field1->elt(i), lencodings->elt(i)), num_trials, "EncodeSlowL", "Total");
		TIMEREP(encoding->encode(R, field1->elt(i), rencodings->elt(i)), num_trials, "EncodeSlowR", "Total");

		TIME(encoding->prepareForManyEncodings(num_trials, config["mem"].as<int>(), false), "PrepForEnc", "Total");
		TIMEREP(encoding->encode(L, field1->elt(i), lencodings->elt(i)), num_trials, "EncodeFastL", "Total");
		TIMEREP(encoding->encode(R, field1->elt(i), rencodings->elt(i)), num_trials, "EncodeFastR", "Total");
		TIMEREP(encoding->encode(L, field2->elt(i), lencodings2->elt(i)), num_trials, "ignoreL", "Total");
		TIMEREP(encoding->encode(R, field2->elt(i), rencodings2->elt(i)), num_trials, "ignoreR", "Total");
		encoding->doneWithManyEncodings();

		printf("Finished encoding test values\n");  fflush(stdout);

		TIMEREP(encoding->add(L, lencodings->elt(i), lencodings2->elt(i), lencodings2->elt(i)), num_trials, "EncAddL", "Total");
		TIMEREP(encoding->add(R, rencodings->elt(i), rencodings2->elt(i), rencodings2->elt(i)), num_trials, "EncAddR", "Total");

		ip_handle_t hL, hR;
    int field_elt_max_bitsize = field->eltSize()*sizeof(digit_t) * 8;
    TIME(hL = encoding->prepareForInnerProduct(lencodings, num_trials, 1, field_elt_max_bitsize, config["mem"].as<int>(), false), "PrepInnerL", "Total");
		TIME(encoding->innerProduct(hL, field1, num_trials, lencodings2->elt(0)), "InnerProdL", "Total");
		encoding->doneWithInnerProduct(hL);

    TIME(hR = encoding->prepareForInnerProduct(rencodings, num_trials, 1, field_elt_max_bitsize, config["mem"].as<int>(), false), "PrepInnerR", "Total");
		TIME(encoding->innerProduct(hR, field1, num_trials, rencodings2->elt(0)), "InnerProdR", "Total");
		encoding->doneWithInnerProduct(hR);

		TIMEREP(encoding->mul(lencodings->elt(i), rencodings->elt(i), prods[i]), num_trials, "Pairing", "Total");

		printf("Finished large encoding tests\n");  fflush(stdout);

		// Measure the time for smaller field elements
		TIME(encoding->prepareForManyEncodings(num_trials, config["mem"].as<int>(), false), "PrepForEnc", "Total");
		TIMEREP(encoding->encode(L, field32->elt(i), lencodings2->elt(i)), num_trials, "EncodeFast32L", "Total");
		TIMEREP(encoding->encode(R, field32->elt(i), rencodings2->elt(i)), num_trials, "EncodeFast32R", "Total");
		encoding->doneWithManyEncodings();

		TIME(hL = encoding->prepareForInnerProduct(lencodings, num_trials, 1, 32, config["mem"].as<int>(), false), "PrepInnerL", "Total");
		TIME(encoding->innerProduct(hL, field32, num_trials, lencodings2->elt(0)), "InnerProd32L", "Total");
		encoding->doneWithInnerProduct(hL);

		TIME(hR = encoding->prepareForInnerProduct(rencodings, num_trials, 1, 32, config["mem"].as<int>(), false), "PrepInnerR", "Total");
		TIME(encoding->innerProduct(hR, field32, num_trials, rencodings2->elt(0)), "InnerProd32R", "Total");
		encoding->doneWithInnerProduct(hR);

		printf("Finished 32-bit encoding tests\n");  fflush(stdout);
	}

	/////////////// Poly Ops ///////////////////////////
  if (option.compare("all") == 0 || option.compare("poly-all") == 0 || option.compare("poly-fast") == 0 || option.compare("poly-slow") == 0 || option.compare("mont-test") == 0) {
		Timer* polyPreComp = timers.newTimer("PolyPreComp", "Total");
		polyPreComp->start();
		PolyTree* tree = new PolyTree(field, field1, num_trials);
		FieldEltArray* denominators = Poly::genLagrangeDenominators(field, *tree->polys[tree->height-1][0], tree, field1, num_trials);
		polyPreComp->stop();

		TIME(Poly::interpolate(field, field2, num_trials, tree, denominators), "PolyInterp", "Total");
		TIME(Poly::interpolateGeometric(field, fieldg0, fieldg1, field2, num_trials), "PolyInterpGeom", "Total");

		// Compare slow vs. optimized polynomial multiplication
		Poly p1(field), p2(field), r(field);
		Poly::polyRand(field, p1, num_trials);
		Poly::polyRand(field, p2, num_trials);
		if (option.compare("poly-all") == 0 || option.compare("poly-fast") == 0) {
			TIME(Poly::mul(p1, p2, p1), "PolyMul", "Total");
		}
		if (option.compare("poly-all") == 0 || option.compare("poly-slow") == 0) {
			TIME(Poly::mulSlow(p1, p2, p1), "PolyMulSlow", "Total");
		}
	}

	total->stop();

	if (config.count("raw")) {
		timers.printRaw();
	} else {
		timers.printStats();
	}
	printf("\n");

	delete field1, field2, field32;
	delete lencodings,  rencodings;
	delete lencodings2, rencodings2;
	delete [] prods;

	delete encoding;
}

ext: cpp

max_stars_repo_name: anthonydelgado/pinocchio

max_issues_repo_name: anthonydelgado/pinocchio

max_forks_repo_name: anthonydelgado/pinocchio


text:
//  Copyright John Maddock 2007.

//  Use, modification and distribution are subject to 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/math/tools/traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/math/distributions.hpp>

using namespace boost::math;

BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<double>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<int>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<bernoulli>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<beta_distribution<> >::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<binomial>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<cauchy>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<chi_squared>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<exponential>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<extreme_value>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<fisher_f>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<gamma_distribution<> >::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<lognormal>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<negative_binomial>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<normal>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<pareto>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<poisson>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<rayleigh>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<students_t>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<triangular>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<uniform>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<weibull>::value);

BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<double>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<int>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<bernoulli>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<beta_distribution<> >::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<binomial>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<cauchy>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<chi_squared>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<exponential>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<extreme_value>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<fisher_f>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<gamma_distribution<> >::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<lognormal>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<negative_binomial>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<normal>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<pareto>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<poisson>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<rayleigh>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<students_t>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<triangular>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<uniform>::value == false);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<weibull>::value == false);


text:
/* test_array_derivatives.cpp - Test derivatives of array expressions

    Copyright (C) 2017 European Centre for Medium-Range Weather Forecasts

    Author: Robin Hogan <r.j.hogan@ecmwf.int>

  Copying and distribution of this file, with or without modification,
  are permitted in any medium without royalty provided the copyright
  notice and this notice are preserved.  This file is offered as-is,
  without any warranty.

*/

#include <adept_arrays.h>

// Arbitrary algorithm converting array of general type A to scalar of
// type S, which may be active or passive
template <class A, class S>
void algorithm(const A& x, S& y) {
  using namespace adept;
  A tmp;
  intVector index(2);
  index << 1, 0;
  tmp = atan2((exp(x) * x), spread<0>(x(index,1),2)) / x(0,0);
  y = sum(tmp);
}

int
main(int argc, const char** argv) {
  using namespace adept;

  Stack stack;

  // Matrix dimension
  static const int N = 2;
  static const Real MAX_FRAC_ERR = 1.0e-5;

  // Perturbation size for numerical calculation
  Real dx = 1.0e-6;

  if (sizeof(Real) < 8) {
    // Single precision only works with larger perturbations
    dx = 1.0e-4;
  }

  // Maximum fractional error
  Real max_frac_err;
  bool error_too_large = false;

  // Input data
  Matrix X(N,N);
  X << 2, 3, 5, 7;

  // Numerical calculation
  std::cout << "NUMERICAL CALCULATION\n";
  Matrix dJ_dx_num(N,N);
  {
    Real J;
    algorithm(X, J);
    std::cout << "J = " << J << "\n";

    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < N; ++j) {
	Matrix Xpert(N,N);
	Xpert = X;
	Xpert(i,j) += dx;
	Real Jpert;
	algorithm(Xpert, Jpert);
	dJ_dx_num(i,j) = (Jpert - J) / dx;
      }
    }
  }

  std::cout << "dJ_dx_num = " << dJ_dx_num << "\n";

  std::cout << "\nNUMERICAL CALCULATION WITH \"FixedArray\"\n";
  Matrix22 dJ_dx_num_FixedArray;
  {
    Real J;
    algorithm(X, J);
    std::cout << "J = " << J << "\n";

    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < N; ++j) {
	Matrix22 Xpert = X;
	Xpert(i,j) += dx;
	Real Jpert;
	algorithm(Xpert, Jpert);
	dJ_dx_num_FixedArray(i,j) = (Jpert - J) / dx;
      }
    }
  }

  std::cout << "dJ_dx_num_FixedArray = " << dJ_dx_num_FixedArray << "\n";

 // Adept calculation with aArray
  std::cout << "\nADEPT CALCULATION WITH \"aArray\"\n";
  Matrix dJ_dx_adept_Array(N,N);
  {
    aMatrix aX = X;
    stack.new_recording();
    aReal aJ;
    algorithm(aX, aJ);
    std::cout << "J = " << aJ << "\n";
    aJ.set_gradient(1.0);
    stack.reverse();

    dJ_dx_adept_Array = aX.get_gradient();
  }

  std::cout << "dJ_dx_adept_Array = " << dJ_dx_adept_Array << "\n";

  max_frac_err = maxval(abs(dJ_dx_adept_Array-dJ_dx_num)/dJ_dx_num);
  if (max_frac_err <= MAX_FRAC_ERR) {
    std::cout << "max fractional error = " << max_frac_err
		<< ": PASSED\n";
  }
  else {
    std::cout << "max fractional error = "
	      << max_frac_err << ": FAILED\n";
    error_too_large = true;
  }
  // Adept calculation with aFixedArray
  std::cout << "\nADEPT CALCULATION WITH \"aFixedArray\"\n";
  Matrix dJ_dx_adept_FixedArray;
  {
    aMatrix22 aX = X;
    stack.new_recording();
    aReal aJ;
    algorithm(aX, aJ);
    std::cout << "J = " << aJ << "\n";
    aJ.set_gradient(1.0);
    stack.reverse();
    dJ_dx_adept_FixedArray = aX.get_gradient();

  }
  std::cout << "dJ_dx_adept_FixedArray = " << dJ_dx_adept_FixedArray << "\n";

  max_frac_err = maxval(abs(dJ_dx_adept_FixedArray-dJ_dx_num)/dJ_dx_num);
  if (max_frac_err <= MAX_FRAC_ERR) {
    std::cout << "max fractional error = " << max_frac_err
		<< ": PASSED\n";
  }
  else {
    std::cout << "max fractional error = "
	      << max_frac_err << ": FAILED\n";
    error_too_large = true;
  }

  std::cout << "\n";

  if (error_too_large) {
    std::cerr << "*** Error: fractional error in the derivatives of some configurations too large\n";

    if (sizeof(Real) < 8) {
      std::cerr << "*** (but you are using less than double precision so it is not surprising)\n";
    }

    return 1;
  }
  else {
    return 0;
  }

}


text:
/* pointer_test.cpp                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 20 Apr 2014
   FreeBSD-style copyright and disclaimer apply

   Tests for pointer reflection.

   \todo Pointers aren't const-checked at the moment.

   Turns out that this is rather difficult to get right because with pointers we
   get multi-layering of constness which makes it impossible to have a single
   bool represent const-ness. As an example:

   int const*      * const*      &
   int      * const*      * const&

   Should they both be const? What would that even mean? What we'd need is a
   list of argument objects that understands both pointer and references. But
   that's just way too complicated for the small feature gain we'd get.

*/

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#define REFLECT_USE_EXCEPTIONS 1

#include "reflect.h"
#include "test_types.h"
#include "types/primitives.h"
#include "types/std/smart_ptr.h"

#include <boost/test/unit_test.hpp>

using namespace reflect;

/******************************************************************************/
/* BASICS                                                                     */
/******************************************************************************/

BOOST_AUTO_TEST_CASE(basics)
{
    const Type* tPtr = type<int*>();
    std::cerr << tPtr->print() << std::endl;

    BOOST_CHECK_EQUAL(type<int const*>(), tPtr);

    BOOST_CHECK(tPtr->isPointer());
    BOOST_CHECK_EQUAL(tPtr->pointer(), "*");
    BOOST_CHECK_EQUAL(tPtr->pointee(), type<int>());

    const Type* tPtrPtr = type<int**>();
    BOOST_CHECK(tPtrPtr->isPointer());
    BOOST_CHECK_EQUAL(tPtrPtr->pointer(), "*");
    BOOST_CHECK_EQUAL(tPtrPtr->pointee(), tPtr);

    BOOST_CHECK_EQUAL(type<int const* const*>(), tPtrPtr);
    BOOST_CHECK_EQUAL(type<int      * const*>(), tPtrPtr);
    BOOST_CHECK_EQUAL(type<int const*      *>(), tPtrPtr);

    auto argPtr = Argument::make<int*>();
    auto argPtrPtr = Argument::make<int**>();
    auto argSharedPtr = Argument::make< std::shared_ptr<int> >();
    BOOST_CHECK_EQUAL(argPtr.isConvertibleTo(argPtr), Match::Exact);
    BOOST_CHECK_EQUAL(argPtr.isConvertibleTo(argPtrPtr), Match::None);
    BOOST_CHECK_EQUAL(argPtr.isConvertibleTo(argSharedPtr), Match::None);
    BOOST_CHECK_EQUAL(argSharedPtr.isConvertibleTo(argSharedPtr), Match::Exact);
}

/******************************************************************************/
/* POINTER                                                                    */
/******************************************************************************/

BOOST_AUTO_TEST_CASE(pointer_test)
{
    typedef test::Object Obj;

    auto doPtr = [] (Obj* obj) { return obj; };
    Function ptrFn("ptr", doPtr);

    auto doPtrPtr = [] (Obj** obj) { return obj; };
    Function ptrPtrFn("ptrPtr", doPtrPtr);

    auto doConstPtr = [] (Obj const* const obj) { return obj; };
    Function constPtrFn("constPtr", doConstPtr);

    BOOST_CHECK_EQUAL(ptrFn.test<void(Obj       )>(), Match::None);
    BOOST_CHECK_EQUAL(ptrFn.test<void(Obj *     )>(), Match::Exact);
    BOOST_CHECK_EQUAL(ptrFn.test<void(Obj **    )>(), Match::None);
    BOOST_CHECK_EQUAL(ptrFn.test<void(Obj const*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(ptrFn.test<Obj       (Obj*)>(), Match::None);
    BOOST_CHECK_EQUAL(ptrFn.test<Obj *     (Obj*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(ptrFn.test<Obj **    (Obj*)>(), Match::None);
    BOOST_CHECK_EQUAL(ptrFn.test<Obj const*(Obj*)>(), Match::Exact);

    BOOST_CHECK_EQUAL(ptrPtrFn.test<void(Obj       )>(), Match::None);
    BOOST_CHECK_EQUAL(ptrPtrFn.test<void(Obj *     )>(), Match::None);
    BOOST_CHECK_EQUAL(ptrPtrFn.test<void(Obj **    )>(), Match::Exact);
    BOOST_CHECK_EQUAL(ptrPtrFn.test<void(Obj const*)>(), Match::None);
    BOOST_CHECK_EQUAL(ptrPtrFn.test<Obj       (Obj**)>(), Match::None);
    BOOST_CHECK_EQUAL(ptrPtrFn.test<Obj *     (Obj**)>(), Match::None);
    BOOST_CHECK_EQUAL(ptrPtrFn.test<Obj **    (Obj**)>(), Match::Exact);
    BOOST_CHECK_EQUAL(ptrPtrFn.test<Obj const*(Obj**)>(), Match::None);

    BOOST_CHECK_EQUAL(constPtrFn.test<void(Obj       )>(), Match::None);
    BOOST_CHECK_EQUAL(constPtrFn.test<void(Obj *     )>(), Match::Exact);
    BOOST_CHECK_EQUAL(constPtrFn.test<void(Obj **    )>(), Match::None);
    BOOST_CHECK_EQUAL(constPtrFn.test<void(Obj const*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(constPtrFn.test<Obj       (Obj const*)>(), Match::None);
    BOOST_CHECK_EQUAL(constPtrFn.test<Obj *     (Obj const*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(constPtrFn.test<Obj **    (Obj const*)>(), Match::None);
    BOOST_CHECK_EQUAL(constPtrFn.test<Obj const*(Obj const*)>(), Match::Exact);

}

BOOST_AUTO_TEST_CASE(pointer_call)
{
    typedef test::Object Obj;

    auto doPtr = [] (Obj* obj) { return obj; };
    Function ptrFn("ptr", doPtr);

    auto doPtrPtr = [] (Obj** obj) { return obj; };
    Function ptrPtrFn("ptrPtr", doPtrPtr);

    auto doConstPtr = [] (Obj const* const obj) { return obj; };
    Function constPtrFn("constPtr", doConstPtr);

    Obj o;
    Obj* po = &o;
    Obj** ppo = &po;
    Obj const* cpo = &o;

    BOOST_CHECK_THROW(ptrFn.call<Obj*>(o  ), Error);
    BOOST_CHECK_EQUAL(ptrFn.call<Obj*>(po ), doPtr(po));
    BOOST_CHECK_THROW(ptrFn.call<Obj*>(ppo), Error);
    BOOST_CHECK_EQUAL(ptrFn.call<Obj*>(cpo), doPtr(po)); // Not an error.
    BOOST_CHECK_THROW(ptrFn.call<Obj*>(Value(o  )), Error);
    BOOST_CHECK_EQUAL(ptrFn.call<Obj*>(Value(po )), doPtr(po));
    BOOST_CHECK_THROW(ptrFn.call<Obj*>(Value(ppo)), Error);
    BOOST_CHECK_EQUAL(ptrFn.call<Obj*>(Value(cpo)), doPtr(po)); // not an error.
    BOOST_CHECK_THROW(ptrFn.call<Obj       >(po), Error);
    BOOST_CHECK_EQUAL(ptrFn.call<Obj *     >(po), doPtr(po));
    BOOST_CHECK_THROW(ptrFn.call<Obj **    >(po), Error);
    BOOST_CHECK_EQUAL(ptrFn.call<Obj const*>(po), doPtr(po));

    BOOST_CHECK_THROW(ptrPtrFn.call<Obj**>(o  ), Error);
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj**>(po ), Error);
    BOOST_CHECK_EQUAL(ptrPtrFn.call<Obj**>(ppo), doPtrPtr(ppo));
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj**>(cpo), Error);
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj**>(Value(o  )), Error);
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj**>(Value(po )), Error);
    BOOST_CHECK_EQUAL(ptrPtrFn.call<Obj**>(Value(ppo)), doPtrPtr(ppo));
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj**>(Value(cpo)), Error);
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj       >(ppo), Error);
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj *     >(ppo), Error);
    BOOST_CHECK_EQUAL(ptrPtrFn.call<Obj **    >(ppo), doPtrPtr(ppo));
    BOOST_CHECK_THROW(ptrPtrFn.call<Obj const*>(ppo), Error);

    BOOST_CHECK_THROW(constPtrFn.call<Obj const*>(o  ), Error);
    BOOST_CHECK_EQUAL(constPtrFn.call<Obj const*>(po ), doConstPtr(po));
    BOOST_CHECK_THROW(constPtrFn.call<Obj const*>(ppo), Error);
    BOOST_CHECK_EQUAL(constPtrFn.call<Obj const*>(cpo), doConstPtr(cpo));
    BOOST_CHECK_THROW(constPtrFn.call<Obj const*>(Value(o  )), Error);
    BOOST_CHECK_EQUAL(constPtrFn.call<Obj const*>(Value(po )), doConstPtr(po));
    BOOST_CHECK_THROW(constPtrFn.call<Obj const*>(Value(ppo)), Error);
    BOOST_CHECK_EQUAL(constPtrFn.call<Obj const*>(Value(cpo)), doConstPtr(cpo));
    BOOST_CHECK_THROW(constPtrFn.call<Obj       >(cpo), Error);
                      constPtrFn.call<Obj *     >(cpo);
    BOOST_CHECK_THROW(constPtrFn.call<Obj **    >(cpo), Error);
    BOOST_CHECK_EQUAL(constPtrFn.call<Obj const*>(cpo), doConstPtr(cpo));

}

/******************************************************************************/
/* CHILD PARENT                                                               */
/******************************************************************************/

BOOST_AUTO_TEST_CASE(childParent_test)
{
    using namespace test;

    auto doChild = [] (Child* c) { return c; };
    Function childFn("child", doChild);

    auto doParent = [] (Parent* p) { return p; };
    Function parentFn("parent", doParent);

    typedef std::shared_ptr<Child> SmartChild;
    auto doSmartChild = [] (SmartChild c) { return c; };
    Function smartChildFn("smartChild", doSmartChild);

    typedef std::shared_ptr<Parent> SmartParent;
    auto doSmartParent = [] (SmartParent p) { return p; };
    Function smartParentFn("smartParent", doSmartParent);

    BOOST_CHECK_EQUAL(childFn.test<Child*(Child*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(childFn.test<Child*(Parent*)>(), Match::None);
    BOOST_CHECK_EQUAL(childFn.test<Child*(SmartChild)>(), Match::None);
    BOOST_CHECK_EQUAL(childFn.test<Parent*(Child*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(childFn.test<SmartChild(Child*)>(), Match::None);

    BOOST_CHECK_EQUAL(parentFn.test<Parent*(Child*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(parentFn.test<Parent*(Parent*)>(), Match::Exact);
    BOOST_CHECK_EQUAL(parentFn.test<Parent*(SmartParent)>(), Match::None);
    BOOST_CHECK_EQUAL(parentFn.test<Child*(Parent*)>(), Match::None);
    BOOST_CHECK_EQUAL(parentFn.test<SmartParent(Parent*)>(), Match::None);

    BOOST_CHECK_EQUAL(smartChildFn.test<SmartChild(Child*)>(), Match::None);
    BOOST_CHECK_EQUAL(smartChildFn.test<SmartChild(SmartChild)>(), Match::Exact);
    BOOST_CHECK_EQUAL(smartChildFn.test<SmartChild(SmartParent)>(), Match::None);
    BOOST_CHECK_EQUAL(smartChildFn.test<Child*(SmartChild)>(), Match::None);
    BOOST_CHECK_EQUAL(smartChildFn.test<SmartParent(SmartChild)>(), Match::Exact);

    BOOST_CHECK_EQUAL(smartParentFn.test<SmartParent(Parent*)>(), Match::None);
    BOOST_CHECK_EQUAL(smartParentFn.test<SmartParent(SmartChild)>(), Match::Exact);
    BOOST_CHECK_EQUAL(smartParentFn.test<SmartParent(SmartParent)>(), Match::Exact);
    BOOST_CHECK_EQUAL(smartParentFn.test<Parent*(SmartParent)>(), Match::None);
    BOOST_CHECK_EQUAL(smartParentFn.test<SmartChild(SmartParent)>(), Match::None);
}

BOOST_AUTO_TEST_CASE(childParent_call)
{
    using namespace test;

    auto doChild = [] (Child* c) { return c; };
    Function childFn("child", doChild);

    auto doParent = [] (Parent* p) { return p; };
    Function parentFn("parent", doParent);

    typedef std::shared_ptr<Child> SmartChild;
    auto doSmartChild = [] (SmartChild c) { return c; };
    Function smartChildFn("smartChild", doSmartChild);

    typedef std::shared_ptr<Parent> SmartParent;
    auto doSmartParent = [] (SmartParent p) { return p; };
    Function smartParentFn("smartParent", doSmartParent);

    Child child;
    Child* pc = &child;
    SmartChild sc(new Child);

    Parent parent;
    Parent* pp = &parent;
    SmartParent sp(new Parent);

    BOOST_CHECK_EQUAL(childFn.call<Child*>(pc), doChild(pc));
    BOOST_CHECK_THROW(childFn.call<Child*>(pp), Error);
    BOOST_CHECK_THROW(childFn.call<Child*>(sc), Error);
    BOOST_CHECK_EQUAL(childFn.call<Parent*>(pc), doChild(pc));
    BOOST_CHECK_THROW(childFn.call<SmartChild>(pc), Error);

    BOOST_CHECK_EQUAL(parentFn.call<Parent*>(pc), doParent(pc));
    BOOST_CHECK_EQUAL(parentFn.call<Parent*>(pp), doParent(pp));
    BOOST_CHECK_THROW(parentFn.call<Parent*>(sp), Error);
    BOOST_CHECK_THROW(parentFn.call<Child*>(pp), Error);
    BOOST_CHECK_THROW(parentFn.call<SmartParent>(pp), Error);

    BOOST_CHECK_THROW(smartChildFn.call<SmartChild>(pc), Error);
    BOOST_CHECK_EQUAL(smartChildFn.call<SmartChild>(sc), doSmartChild(sc));
    BOOST_CHECK_THROW(smartChildFn.call<SmartChild>(sp), Error);
    BOOST_CHECK_THROW(smartChildFn.call<Child*>(sc), Error);
    BOOST_CHECK_EQUAL(smartChildFn.call<SmartParent>(sc), doSmartChild(sc));

    BOOST_CHECK_THROW(smartParentFn.call<SmartParent>(pp), Error);
    BOOST_CHECK_EQUAL(smartParentFn.call<SmartParent>(sc), doSmartParent(sc));
    BOOST_CHECK_EQUAL(smartParentFn.call<SmartParent>(sp), doSmartParent(sp));
    BOOST_CHECK_THROW(smartParentFn.call<Parent*>(sp), Error);
    BOOST_CHECK_THROW(smartParentFn.call<SmartChild>(sp), Error);
}

/******************************************************************************/
/* SMART PTR                                                                  */
/******************************************************************************/

template<typename Ptr>
void testSmartPtr(const std::string& pointer)
{
    typedef test::NotConstructible Obj;

    const Type* tPtr = type<Ptr>();
    std::cerr << tPtr->print() << std::endl;

    BOOST_CHECK(tPtr->isPointer());
    BOOST_CHECK_EQUAL(tPtr->pointer(), pointer);
    BOOST_CHECK_EQUAL(tPtr->pointee(), type<Obj>());

    Obj* po = Obj::make();
    Value vPtr = tPtr->construct(po);

    auto& obj = (*vPtr).get<Obj>();
    auto& sharedPtr = vPtr.get<Ptr>();

    BOOST_CHECK(vPtr); // operator bool()
    BOOST_CHECK(vPtr == sharedPtr); // operator==
    BOOST_CHECK_EQUAL(&obj, po);
    BOOST_CHECK_EQUAL(sharedPtr.get(), po);
    BOOST_CHECK_EQUAL(vPtr.call<Obj*>("get"), po);

    vPtr.call<void>("reset", Obj::make());

    BOOST_CHECK(vPtr); // operator bool()
    BOOST_CHECK_NE(vPtr.call<Obj*>("get"), po);

    vPtr.call<void>("reset");
    BOOST_CHECK(!vPtr); // operator bool()
    BOOST_CHECK(vPtr.call<Obj*>("get") == nullptr);

}

BOOST_AUTO_TEST_CASE(sharedPtr)
{
    typedef test::NotConstructible Obj;
    testSmartPtr< std::shared_ptr<Obj> >("std::shared_ptr");
}

BOOST_AUTO_TEST_CASE(uniquePtr)
{
    typedef test::NotConstructible Obj;
    testSmartPtr< std::unique_ptr<Obj> >("std::unique_ptr");
}

/******************************************************************************/
/* TODO                                                                       */
/******************************************************************************/

#if 0 // \todo Useful use cases that are currenty not supported.

BOOST_AUTO_TEST_CASE(null)
{
    Function nullFn("null", [] (test::Object* o) {});
    nullFn.call<void>(nullptr);
}

#endif

max_stars_repo_name: unbornchikken/reflect-cpp

max_issues_repo_name: unbornchikken/reflect-cpp

max_forks_repo_name: unbornchikken/reflect-cpp


text:
/*
	Copyright (C) 2003-2014 by David White <davewx7@gmail.com>

	This software is provided 'as-is', without any express or implied
	warranty. In no event will the authors be held liable for any damages
	arising from the use of this software.

	Permission is granted to anyone to use this software for any purpose,
	including commercial applications, and to alter it and redistribute it
	freely, subject to the following restrictions:

	   1. The origin of this software must not be misrepresented; you must not
	   claim that you wrote the original software. If you use this software
	   in a product, an acknowledgement in the product documentation would be
	   appreciated but is not required.

	   2. Altered source versions must be plainly marked as such, and must not be
	   misrepresented as being the original software.

	   3. This notice may not be removed or altered from any source
	   distribution.
*/

#include <cstddef>
#include <algorithm>
#include <boost/algorithm/string/replace.hpp>
#include <deque>
#include <iostream>

#include <SDL.h>

#if !defined(_MSC_VER)
#include <sys/time.h>
#endif

#include "asserts.hpp"
#include "compress.hpp"
#include "filesystem.hpp"
#include "formatter.hpp"
#include "json_parser.hpp"
#include "http_server.hpp"
#include "string_utils.hpp"
#include "utils.hpp"
#include "unit_test.hpp"
#include "variant.hpp"

using boost::asio::ip::tcp;

namespace http
{
	namespace {
		typedef web_server::socket_ptr socket_ptr;
	}
	struct WebServerProxyInfo {
		WebServerProxyInfo(web_server& server, uint32_t session_id, boost::asio::io_service& io_service, const std::string& host, const std::string& port);
		web_server* server;
		uint32_t session_id;
		std::string host;
		std::string port;
		std::shared_ptr<tcp::resolver> resolver;
		std::shared_ptr<tcp::resolver::query> resolver_query;
		tcp::resolver::iterator endpoint_iterator;
		socket_ptr socket;
	};

	namespace {
		typedef std::shared_ptr<WebServerProxyInfo> WebServerProxyInfoPtr;

		void proxy_connect(WebServerProxyInfoPtr info);

		void handle_proxy_send(WebServerProxyInfoPtr info, std::shared_ptr<std::string> msg, const boost::system::error_code& error, size_t nbytes)
		{
			if(error) {
				LOG_ERROR("Proxy send failed: " << info->host << ":" << info->port);
			} else {
				if(info->server) {
					info->server->start_receive(info->socket);
				}
			}
		}

		void handle_proxy_connect(WebServerProxyInfoPtr info, const boost::system::error_code& error)
		{
			if(error) {
				++(info->endpoint_iterator);
				proxy_connect(info);
			} else {
				std::shared_ptr<std::string> msg(new std::string);
				msg->resize(4);
				memcpy(&(*msg)[0], &info->session_id, 4);
				boost::asio::async_write(info->socket->socket, boost::asio::buffer(*msg),
				  std::bind(handle_proxy_send, info, msg, std::placeholders::_1, std::placeholders::_2));
			}
		}

		void proxy_connect(WebServerProxyInfoPtr info)
		{
			if(info->endpoint_iterator == tcp::resolver::iterator()) {
				LOG_ERROR("Failed to connect to proxy: " << info->host);
				return;
			}

			boost::asio::async_connect(info->socket->socket,
			  info->endpoint_iterator,
			  std::bind(&handle_proxy_connect, info, std::placeholders::_1));
		}

		void handle_resolve_proxy(WebServerProxyInfoPtr info, const boost::system::error_code& error, tcp::resolver::iterator endpoint_iterator)
		{
			if(!error) {
				info->endpoint_iterator = endpoint_iterator;
				proxy_connect(info);

			} else {
				LOG_ERROR("Could not resolve proxy server: " << info->host << ":" << info->port);
			}
		}

		std::shared_ptr<WebServerProxyInfo> create_web_server_proxy(web_server& server_, uint32_t session_id_, boost::asio::io_service& io_service_, const std::string& host_, const std::string& port_)
		{
			std::shared_ptr<WebServerProxyInfo> result(new WebServerProxyInfo(server_, session_id_,io_service_, host_, port_));
			result->resolver->async_resolve(*result->resolver_query,
		  	   std::bind(handle_resolve_proxy, result, std::placeholders::_1, std::placeholders::_2));
			return result;
		}
	}

	WebServerProxyInfo::WebServerProxyInfo(web_server& server_, uint32_t session_id_, boost::asio::io_service& io_service_, const std::string& host_, const std::string& port_)
	  : server(&server_), session_id(session_id_), host(host_), port(port_),
	    resolver(new tcp::resolver(io_service_)),
		resolver_query(new tcp::resolver::query(tcp::resolver::query::protocol_type::v4(), host_.c_str(), port_.c_str())),
		socket(new web_server::SocketInfo(io_service_))
	{
	}

	web_server::SocketInfo::SocketInfo(boost::asio::io_service& service)
	  : socket(service), client_version(0), supports_deflate(false)
	{
	}

	web_server::web_server(boost::asio::io_service& io_service, int port)
	  : io_service_(io_service)
	{
		if(port) {
			acceptor_.reset(new boost::asio::ip::tcp::acceptor(io_service, tcp::endpoint(tcp::v4(), port)));
			boost::asio::socket_base::reuse_address option(true);
			acceptor_->set_option(option);
		}

		start_accept();
	}

	web_server::~web_server()
	{
		if(acceptor_) {
			acceptor_->close();
		}

		for(auto p : proxies_) {
			p->server = nullptr;
		}
	}

	void web_server::connect_proxy(uint32_t session_id, const std::string& host, const std::string& port)
	{
		std::shared_ptr<WebServerProxyInfo> proxy = create_web_server_proxy(*this, session_id, io_service_, host, port);
		proxies_.push_back(proxy);

	}

	void web_server::start_accept()
	{
		if(!acceptor_) {
			return;
		}

		socket_ptr socket(new SocketInfo(io_service_));
		acceptor_->async_accept(socket->socket, std::bind(&web_server::handle_accept, this, socket, std::placeholders::_1));
	}

	namespace {
	int nconnections = 0;
	}

	void web_server::handle_accept(socket_ptr socket, const boost::system::error_code& error)
	{
		if(error) {
			LOG_ERROR("ERROR IN ACCEPT");
			return;
		}

		start_receive(socket);
		start_accept();
	}

	void web_server::keepalive_socket(socket_ptr socket)
	{
		start_receive(socket);
	}

	void web_server::start_receive(socket_ptr socket, receive_buf_ptr recv_buf)
	{
		if(!recv_buf) {
			recv_buf.reset(new receive_buf);
		}

		buffer_ptr buf(new boost::array<char, 64*1024>);
		socket->socket.async_read_some(boost::asio::buffer(*buf), std::bind(&web_server::handle_receive, this, socket, buf, std::placeholders::_1, std::placeholders::_2, recv_buf));
	}

	void web_server::handle_receive(socket_ptr socket, buffer_ptr buf,
		const boost::system::error_code& e,
		size_t nbytes,
		receive_buf_ptr recv_buf)
	{
		if(e) {
			//TODO: handle error
			LOG_ERROR("SOCKET ERROR: " << e.message());
			disconnect(socket);
			return;
		}

		handle_incoming_data(socket, &(*buf)[0], &(*buf)[0] + nbytes, recv_buf);
	}

	void web_server::handle_incoming_data(socket_ptr socket, const char* i1, const char* i2, receive_buf_ptr recv_buf)
	{
		recv_buf->msg += std::string(i1, i2);
		LOG_INFO("HANDLE INCOMING: " << (int)recv_buf->msg.size() << " / " << (int)recv_buf->wanted);

		if(recv_buf->wanted > 0 && recv_buf->msg.size() < recv_buf->wanted) {
			start_receive(socket, recv_buf);
			return;
		}

		timeval before, after;
		gettimeofday(&before, nullptr);
		handle_message(socket, recv_buf);
		gettimeofday(&after, nullptr);

		const int ms = (after.tv_sec - before.tv_sec)*1000 + (after.tv_usec - before.tv_usec)/1000;
		LOG_INFO("handle_incoming_data time: " << ms << "ms");
	}

	namespace {
	struct Request {
		std::string path;
		std::map<std::string, std::string> args;
	};

	Request parse_request(const std::string& str) {
		std::string::const_iterator end_path = std::find(str.begin(), str.end(), '?');
		Request request;
		request.path.assign(str.begin(), end_path);

		LOG_INFO("PATH: '" << request.path << "'");

		if(end_path != str.end()) {
			++end_path;

			std::vector<std::string> args = util::split(std::string(end_path, str.end()), '&');
			for(const std::string& a : args) {
				std::string::const_iterator equal_itor = std::find(a.begin(), a.end(), '=');
				if(equal_itor != a.end()) {
					const std::string name(a.begin(), equal_itor);
					const std::string value(equal_itor+1, a.end());
					request.args[name] = value;
				}
			}
		}

		return request;
	}

	}

	void web_server::handle_message(socket_ptr socket, receive_buf_ptr recv_buf)
	{
		for(auto& p : proxies_) {
			if(p->socket == socket) {
				p->socket.reset(new SocketInfo(io_service_));
				proxy_connect(p);
				break;
			}
		}

		const std::string& msg = recv_buf->msg;
		if(msg.size() < 16) {
			LOG_INFO("CLOSESOCKB");
			disconnect(socket);
			return;
		}

		if(std::equal(msg.begin(), msg.begin()+5, "POST ")) {

			const char* payload = nullptr;
			const char* payload1 = strstr(msg.c_str(), "\n\n");
			const char* payload2 = strstr(msg.c_str(), "\r\n\r\n");
			if(payload1) {
				payload1 += 2;
				payload = payload1;
			}

			if(payload2 && (!payload1 || payload2 < payload1)) {
				payload2 += 4;
				payload = payload2;
			}

			std::string headers;
			if(payload) {
				headers = std::string(msg.c_str(), payload);
			} else {
				headers = msg;
			}

			environment env = parse_http_headers(headers);

			static const std::string UserAgentStr("user-agent");
			auto user_agent_itor = env.find(UserAgentStr);
			if(user_agent_itor != env.end()) {
				const char* p = strstr(user_agent_itor->second.c_str(), " 1.");
				if(p != nullptr) {
					p += 3;

					socket->client_version = atoi(p);
				}
			}

			static const std::string AcceptEncodingStr("accept-encoding");
			auto encoding_itor = env.find(AcceptEncodingStr);
			if(encoding_itor != env.end()) {
				if(strstr(encoding_itor->second.c_str(), "deflate") || strstr(encoding_itor->second.c_str(), "Deflate")) {
					socket->supports_deflate = true;
				}
			}

			const int content_length = atoi(env["content-length"].c_str());
			LOG_DEBUG("PARSE content-length: " << content_length);

			const auto payload_len = payload ? (msg.c_str() + msg.size() - payload) : 0;

			LOG_DEBUG("PAYLOAD LEN: " << payload_len << " < " << content_length);
			if(!payload || payload_len < content_length) {
				if(payload_len) {
					recv_buf->wanted = msg.size() + (content_length - payload_len);
				}
				start_receive(socket, recv_buf);
				return;
			}

			variant doc;

			try {
				doc = parse_message(std::string(payload, payload + payload_len));
			} catch(json::ParseError& e) {
				LOG_ERROR("ERROR PARSING JSON: " << e.errorMessage());
				sys::write_file("./error_payload2.txt", std::string(payload));
			} catch(...) {
				LOG_ERROR("UNKNOWN ERROR PARSING JSON");
			}

			if(!doc.is_null()) {
				handlePost(socket, doc, env, msg);
				return;
			}
		} else if(std::equal(msg.begin(), msg.begin()+4, "GET ")) {
			std::string::const_iterator begin_url = msg.begin() + 4;
			std::string::const_iterator end_url = std::find(begin_url, msg.end(), ' ');
			std::string::const_iterator begin_args = std::find(begin_url, end_url, '?');
			std::map<std::string, std::string> args;
			std::string url_base(begin_url, begin_args);
			if(begin_args != end_url) {
				begin_args++;
				while(begin_args != end_url) {
					std::string::const_iterator eq = std::find(begin_args, end_url, '=');
					if(eq == end_url) {
						break;
					}

					std::string::const_iterator amp = std::find(eq, end_url, '&');
					std::string name(begin_args, eq);
					std::string value(eq+1, amp);
					args[name] = value;

					begin_args = amp;
					if(begin_args == end_url) {
						break;
					}

					++begin_args;
				}
			}

			handleGet(socket, url_base, args);

			return;
		}

		disconnect(socket);
	}

	void web_server::handle_send(socket_ptr socket, const boost::system::error_code& e, size_t nbytes, size_t max_bytes, std::shared_ptr<std::string> buf)
	{
		if(e) {
			disconnect(socket);
		} else if(nbytes == max_bytes) {
			//LOG_INFO("COMPLETE_MSG(((" << *buf << ")))");
			keepalive_socket(socket);
		}
	}

	void web_server::disconnect_socket(socket_ptr socket)
	{
		socket->socket.close();
		--nconnections;
	}

	void web_server::disconnect(socket_ptr socket)
	{
		for(auto& p : proxies_) {
			if(p->socket == socket) {
				p->socket.reset(new SocketInfo(io_service_));
				proxy_connect(p);
				break;
			}
		}

		disconnect_socket(socket);
	}

	void web_server::send_msg(socket_ptr socket, const std::string& type, const std::string& msg_ref, const std::string& header_parms)
	{
		std::string compressed_buf;
		std::string compress_header;
		const std::string* msg_ptr = &msg_ref;
		if(socket->supports_deflate && msg_ref.size() > 1024 && (header_parms.empty() || strstr(header_parms.c_str(), "Content-Encoding") == nullptr)) {
			compressed_buf = zip::compress(msg_ref);
			msg_ptr = &compressed_buf;

			compress_header = "Content-Encoding: deflate\r\n";
		}

		const std::string& msg = *msg_ptr;

		std::stringstream buf;
		buf <<
			"HTTP/1.1 200 OK\r\n"
			"Date: " << get_http_datetime() << "\r\n"
			"Connection: close\r\n"
			"Server: Wizard/1.0\r\n"
			"Accept-Ranges: bytes\r\n"
			"Access-Control-Allow-Origin: *\r\n"
			"Content-Type: " << type << "\r\n"
			"Content-Length: " << std::dec << (int)msg.size() << "\r\n" <<
			compress_header <<
			"Last-Modified: " << get_http_datetime() << "\r\n" <<
			(header_parms.empty() ? "" : header_parms + "\r\n")
			<< "\r\n";

		std::shared_ptr<std::string> str(new std::string(buf.str()));
		*str += msg;

		boost::asio::async_write(socket->socket, boost::asio::buffer(*str),
								 std::bind(&web_server::handle_send, this, socket, std::placeholders::_1, std::placeholders::_2, str->size(), str));
	}

	void web_server::send_404(socket_ptr socket)
	{
		std::stringstream buf;
		buf <<
			"HTTP/1.1 404 NOT FOUND\r\n"
			"Date: " << get_http_datetime() << "\r\n"
			"Connection: close\r\n"
			"Server: Wizard/1.0\r\n"
			"Accept-Ranges: none\r\n"
			"\r\n";
		std::shared_ptr<std::string> str(new std::string(buf.str()));
		boost::asio::async_write(socket->socket, boost::asio::buffer(*str),
					std::bind(&web_server::handle_send, this, socket, std::placeholders::_1, std::placeholders::_2, str->size(), str));
	}

	variant web_server::parse_message(const std::string& msg) const
	{
		return json::parse(msg, json::JSON_PARSE_OPTIONS::NO_PREPROCESSOR);
	}

}

namespace {
using namespace http;
class test_web_server : public http::web_server {
public:
	test_web_server(boost::asio::io_service& io_service) : web_server(io_service) {}
	void handlePost(socket_ptr socket, variant doc, const environment& env, const std::string& raw_msg) override {

		send_msg(socket, "text/json", "{ \"type\": \"ok\" }", "");
	}
	void handleGet(socket_ptr socket, const std::string& url, const std::map<std::string, std::string>& args) override {
		send_msg(socket, "text/json", "{ \"type\": \"ok\" }", "");
	}

private:
};
}

COMMAND_LINE_UTILITY(test_http_server) {
	using namespace http;

	boost::asio::io_service io_service;
	test_web_server server(io_service);

	io_service.run();
}

max_stars_repo_name: gamobink/anura

max_issues_repo_name: gamobink/anura

max_forks_repo_name: gamobink/anura


text:
#ifndef MOCHIMOCHI_NHERD_HPP_
#define MOCHIMOCHI_NHERD_HPP_

#include <Eigen/Dense>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
#include <functional>
#include "../../functions/enumerate.hpp"

class NHERD {
private :
  const std::size_t kDim;
  const double kC;
  const int kDiagonal;

private :
  Eigen::VectorXd _covariances;
  Eigen::VectorXd _means;

private :
  std::function<double(double, double, double)> _compute_covariance;

public :
  NHERD(const std::size_t dim, const double C, const int diagonal = 0)
    : kDim(dim),
      kC(C),
      kDiagonal(diagonal),
      _covariances(Eigen::VectorXd::Ones(kDim)),
      _means(Eigen::VectorXd::Zero(kDim)) {

    static_assert(std::numeric_limits<decltype(dim)>::max() > 0, "Dimension Error. (Dimension > 0)");
    static_assert(std::numeric_limits<decltype(C)>::max() > 0, "Hyper Parameter Error. (C > 0)");

    // int diagonal : switching the diagonal covariance
    // 0 : Full covariance
    // 1 : Exact covariance
    // 2 : Project covariance
    // 3 : Drop covariance
    switch(kDiagonal) {
    case 0 :
      _compute_covariance = [=](const auto covariance, const auto confidence, const auto value) {
        const auto v = covariance * value;
        return covariance - (v * v * (kC * kC * confidence + 2 * kC) / std::pow((1.0 + kC * confidence), 2));
      };
      break;
    case 1 :
      _compute_covariance = [=](const auto covariance, const auto confidence, const auto value) {
        return covariance / std::pow(1.0 + kC * value * value * covariance, 2);
      };
      break;
    case 2 :
      _compute_covariance = [=](const auto covariance, const auto confidence, const auto value) {
        return 1.0 / ((1.0 / covariance) + (2 * kC + kC * kC * confidence) * value * value);
      };
      break;
    case 3 :
      _compute_covariance = [=](const auto covariance, const auto confidence, const auto value) {
        const auto v = (std::pow(covariance * value, 2) * (kC * kC * confidence + 2 * kC) / std::pow(1.0 + kC * confidence, 2));
        return covariance - v;
      };
      break;
    default:
      std::runtime_error("Error in switching the diagonal covariance.");
    }

  }

  virtual ~NHERD() { }

private :

  double suffer_loss(const double margin, const int label) const {
    return margin * label;
  }

  double compute_margin(const Eigen::VectorXd& x) const {
    return _means.dot(x);
  }

  double compute_confidence(const Eigen::VectorXd& feature) const {
    auto confidence = 0.0;
    functions::enumerate(feature.data(), feature.data() + feature.size(), 0,
                         [&](const int index, const double value) {
                           confidence += _covariances[index] * value * value;
                         });
    return confidence;
  }

public :

  bool update(const Eigen::VectorXd& feature, const int label) {
    const auto margin = compute_margin(feature);

    if (suffer_loss(margin, label) >= 1.0) { return false; }

    const auto confidence = compute_confidence(feature);
    const auto alpha = std::max(0.0, 1.0 - label * margin) / (confidence + 1 / kC) ;

    functions::enumerate(feature.data(), feature.data() + feature.size(), 0,
                       [&](const std::size_t index, const double value) {
                         _means[index] += alpha * label * _covariances[index] * value;
                         _covariances[index] = _compute_covariance(_covariances[index], confidence, value);
                       });
    return true;
  }

  int predict(const Eigen::VectorXd& x) const {
    return compute_margin(x) > 0.0 ? 1 : -1;
  }

  Eigen::VectorXd get_means(void) const {
    return _means;
  }

  void save(const std::string& filename) {
    std::ofstream ofs(filename);
    assert(ofs);
    boost::archive::text_oarchive oa(ofs);
    oa << *this;
    ofs.close();
  }

  void load(const std::string& filename) {
    std::ifstream ifs(filename);
    assert(ifs);
    boost::archive::text_iarchive ia(ifs);
    ia >> *this;
    ifs.close();
  }

private :
  friend class boost::serialization::access;
  BOOST_SERIALIZATION_SPLIT_MEMBER();
  template <class Archive>
  void save(Archive& ar, const unsigned int version) const {
    std::vector<double> covariances_vector(_covariances.data(), _covariances.data() + _covariances.size());
    std::vector<double> means_vector(_means.data(), _means.data() + _means.size());
    ar & boost::serialization::make_nvp("covariances", covariances_vector);
    ar & boost::serialization::make_nvp("means", means_vector);
    ar & boost::serialization::make_nvp("dimension", const_cast<std::size_t&>(kDim));
    ar & boost::serialization::make_nvp("C", const_cast<double&>(kC));
  }

  template <class Archive>
  void load(Archive& ar, const unsigned int version) {
    std::vector<double> covariances_vector;
    std::vector<double> means_vector;
    ar & boost::serialization::make_nvp("covariances", covariances_vector);
    ar & boost::serialization::make_nvp("means", means_vector);
    ar & boost::serialization::make_nvp("dimension", const_cast<std::size_t&>(kDim));
    ar & boost::serialization::make_nvp("C", const_cast<double&>(kC));
    _covariances = Eigen::Map<Eigen::VectorXd>(&covariances_vector[0], covariances_vector.size());
    _means = Eigen::Map<Eigen::VectorXd>(&means_vector[0], means_vector.size());
  }
};

#endif //MOCHIMOCHI_NHERD_HPP_

ext: hpp

max_stars_repo_name: olanleed/MochiMochi

max_issues_repo_name: olanleed/MochiMochi

max_forks_repo_name: olanleed/MochiMochi