<commit_before>//-----------------------------------------------------------
//
//    Copyright (C) 2014 by the deal.II authors
//
//    This file is subject to LGPL and may not be distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//-----------------------------------------------------------

//
// Simple example of solving the following nonlinear system of
// equations
//
// x(0)^2 + x(1)^2 -1 = 0
//      x(1) - x(0)^2 = 0
//
// using NOX

#include "tests.h"
#include "newton_solver.h"

class SimpleNonlinearProblem:
  public NewtonArgument
{
public:

  unsigned int n_dofs() const
  {
    return 2;
  }

  virtual void output_step(Vector<double> &solution,
                           const unsigned int step_number)
  {
    std::cout<<"Test"<<std::endl;
  }

  /** For newton solver, we need a
  residual function. */
  virtual int residual(Vector<double> &dst,
                       const Vector<double> &src_yy)
  {
    dst(0) = src_yy(0)*src_yy(0) + src_yy(1)*src_yy(1) - 1.0;
    dst(1) = src_yy(1) - src_yy(0)*src_yy(0);
    cout<<"In: "<<src_yy<<endl;
    cout<<"Out: "<<dst<<endl;
    return 0;
  }
  /** Jacobian vector product for newton solver. */
  virtual int jacobian(Vector<double> &dst,
                       const Vector<double> &src_yy,
                       const Vector<double> &src)
  {
    double J11 = 2.0*src_yy(0);
    double J12 = 2.0*src_yy(1);
    double J21 = -2.0*src_yy(0);
    double J22 = 1.0;

    dst(0) = J11*src(0) + J12*src(1);
    dst(1) = J21*src(0) + J22*src(1);
    return 0;
  }

  /** Setup Jacobian preconditioner for Newton. */
  virtual int setup_jacobian_prec(const Vector<double> &src_yy)
  {
    return 0;
  }

  /** Jacobian inverse preconditioner
  vector product for newton solver. */
  virtual int jacobian_prec(Vector<double> &dst,
                            const Vector<double> &src_yy,
                            const Vector<double> &src)
  {
    double P11 = 2.0*src_yy(0);
    double P22 = 1.0;

    dst(0) = src(0)/P11;
    dst(1) = src(1)/P22;
    return 0;
  }

  /** Jacobian preconditioner
  vector product for newton solver. */
  virtual int jacobian_prec_prod(Vector<double> &dst,
                                 const Vector<double> &src_yy,
                                 const Vector<double> &src)
  {
    double P11 = 2.0*src_yy(0);
    double P22 = -2.0*src_yy(0);

    dst(0) = src(0)*P11;
    dst(1) = src(1)*P22;
    return 0;
  }

};

int main ()
{
  initlog();
  deallog << 0 << std::endl;

  SimpleNonlinearProblem simple_problem;
  NewtonSolver solver(simple_problem);

  Vector<double> solution(2);
  solution(0) = 1.0;
  solution(1) = 1.0;

  solver.solve(solution,30);

  deallog<<"Computed Solution: {"<<solution(0)<<","<<solution(1)<<"}"<<std::endl;
}
<commit_msg>Fixed test.<commit_after>//-----------------------------------------------------------
//
//    Copyright (C) 2014 by the deal.II authors
//
//    This file is subject to LGPL and may not be distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//-----------------------------------------------------------

//
// Simple example of solving the following nonlinear system of
// equations
//
// x(0)^2 + x(1)^2 -1 = 0
//      x(1) - x(0)^2 = 0
//
// using NOX

#include "tests.h"
#include "newton_solver.h"

class SimpleNonlinearProblem:
  public NewtonArgument
{
public:

  unsigned int n_dofs() const
  {
    return 2;
  }

  virtual void output_step(Vector<double> &solution,
                           const unsigned int step_number)
  {
    std::cout<<"Test"<<std::endl;
  }

  /** For newton solver, we need a
  residual function. */
  virtual int residual(Vector<double> &dst,
                       const Vector<double> &src_yy)
  {
    dst(0) = src_yy(0)*src_yy(0) + src_yy(1)*src_yy(1) - 1.0;
    dst(1) = src_yy(1) - src_yy(0)*src_yy(0);
    std::cout<<"In: "<<src_yy<<std::endl;
    std::cout<<"Out: "<<dst<<std::endl;
    return 0;
  }
  /** Jacobian vector product for newton solver. */
  virtual int jacobian(Vector<double> &dst,
                       const Vector<double> &src_yy,
                       const Vector<double> &src)
  {
    double J11 = 2.0*src_yy(0);
    double J12 = 2.0*src_yy(1);
    double J21 = -2.0*src_yy(0);
    double J22 = 1.0;

    dst(0) = J11*src(0) + J12*src(1);
    dst(1) = J21*src(0) + J22*src(1);
    return 0;
  }

  /** Setup Jacobian preconditioner for Newton. */
  virtual int setup_jacobian_prec(const Vector<double> &src_yy)
  {
    return 0;
  }

  /** Jacobian inverse preconditioner
  vector product for newton solver. */
  virtual int jacobian_prec(Vector<double> &dst,
                            const Vector<double> &src_yy,
                            const Vector<double> &src)
  {
    double P11 = 2.0*src_yy(0);
    double P22 = 1.0;

    dst(0) = src(0)/P11;
    dst(1) = src(1)/P22;
    return 0;
  }

  /** Jacobian preconditioner
  vector product for newton solver. */
  virtual int jacobian_prec_prod(Vector<double> &dst,
                                 const Vector<double> &src_yy,
                                 const Vector<double> &src)
  {
    double P11 = 2.0*src_yy(0);
    double P22 = -2.0*src_yy(0);

    dst(0) = src(0)*P11;
    dst(1) = src(1)*P22;
    return 0;
  }

};

int main (int argc, char **argv)
{
  Utilities::MPI::MPI_InitFinalize init(argc, argv, numbers::invalid_unsigned_int);
  initlog();
  deallog << 0 << std::endl;

  SimpleNonlinearProblem simple_problem;
  NewtonSolver solver(simple_problem);

  Vector<double> solution(2);
  solution(0) = 1.0;
  solution(1) = 1.0;

  solver.solve(solution,30);

  deallog<<"Computed Solution: {"<<solution(0)<<","<<solution(1)<<"}"<<std::endl;
}
<|endoftext|>


<commit_before>
#include <iostream>
#include <iomanip>

#include <openvibe/ovITimeArithmetics.h>

using namespace OpenViBE;
using namespace std;

int main(int argc, char *argv[])
{
	uint64 samplingRates[] = {100,128,200,400,512,1000};

	int retVal = 0;

	uint64 secsAndBackTolerance = {ITimeArithmetics::secondsToTime(0.005)};

	cout << "To seconds and back conversion tolerance has been set to " << ITimeArithmetics::timeToSeconds(secsAndBackTolerance) << " secs\n\n";

	{
		cout << "--\n Test 'time to sample and back' using predefined times \n--\n";

		uint64 timeNow[] = {ITimeArithmetics::secondsToTime(0.0),
			ITimeArithmetics::secondsToTime(1.0),
			ITimeArithmetics::secondsToTime(1.5),
			ITimeArithmetics::secondsToTime(2.0),
			ITimeArithmetics::secondsToTime(128.0)};

		cout << " " << setw(6) << "Rate"
			<< " " << setw(10) << "Sample"
			<< " " << setw(15) << "Time"
			<< " " << setw(15) << "TimeInv"
			<< " " << setw(5)  << "Secs"
			<< " " << setw(15) << "TimeInv2"
			<< "\n";
		for(int i=0;i<sizeof(samplingRates)/sizeof(samplingRates[0]);i++) {
			for(int j=0;j<sizeof(timeNow)/sizeof(timeNow[0]);j++) {
				uint64 sampleIdx = ITimeArithmetics::timeToSampleIndex(samplingRates[i], timeNow[j]);
				uint64 timeFromSample =  ITimeArithmetics::sampleIndexToTime(samplingRates[i], sampleIdx);
				float64 secondsFromTime = ITimeArithmetics::timeToSeconds(timeNow[j]);
				uint64 timeFromSeconds = ITimeArithmetics::secondsToTime(secondsFromTime);
				cout << " " << setw(6) << samplingRates[i]
					<< " " << setw(10) << sampleIdx
					<< " " << setw(15) << timeNow[j]
					<< " " << setw(15) << timeFromSample
					<< " " << setw(5)  << secondsFromTime
					<< " " << setw(15) << timeFromSeconds;
				boolean hadError = false;
				if(timeFromSample != timeNow[j]) {
					cout << "  Error: Converting time to sample and back don't match\n";
					retVal |= 1;
					hadError = true;
				}
				if(std::abs((int64)timeFromSeconds - (int64)timeNow[j]) > (int64) secsAndBackTolerance) {
					cout << "  Error: Converting time to seconds and back don't match\n";
					retVal |= 2;
					hadError = true;
				}
				if(!hadError) {
					cout << " Ok\n";
				}
			}
		}
	}

	{
		cout << "--\n Test 'sample to time and back' using predefined samples\n--\n";

		uint64 sampleIdxs[] = {0,1,1000,1021,1024};

		cout << " " << setw(6) << "Rate"
			<< " " << setw(10) << "Sample"
			<< " " << setw(15) << "SampleInv"
			<< " " << setw(15) << "Time"
			<< " " << setw(15) << "Secs"
			<< " " << setw(15) << "TimeInv2"
			<< "\n";
		for(int i=0;i<sizeof(samplingRates)/sizeof(samplingRates[0]);i++) {
			for(int j=0;j<sizeof(sampleIdxs)/sizeof(sampleIdxs[0]);j++) {
				uint64 timeFromSample =  ITimeArithmetics::sampleIndexToTime(samplingRates[i], sampleIdxs[j]);
				float64 secondsFromTime = ITimeArithmetics::timeToSeconds(timeFromSample);
				uint64 sampleFromTime =  ITimeArithmetics::timeToSampleIndex(samplingRates[i], timeFromSample);
				uint64 timeFromSeconds = ITimeArithmetics::secondsToTime(secondsFromTime);

				cout << " " << setw(6) << samplingRates[i]
					<< " " << setw(10) << sampleIdxs[j]
					<< " " << setw(15) << sampleFromTime
					<< " " << setw(15) << timeFromSample
					<< " " << setw(15) << secondsFromTime
					<< " " << setw(15) << timeFromSeconds;
				boolean hadError = false;
				if(sampleIdxs[j] != sampleFromTime) {
					cout << "  Error: Converting sample to time and back don't match\n";
					retVal |= 3;
					hadError = true;
				}
				if(std::abs((int64)timeFromSeconds - (int64)timeFromSample) > (int64)secsAndBackTolerance) {
					cout << "  Error: Converting time to seconds and back don't match\n";
					retVal |= 4;
					hadError = true;
				}
				if(!hadError) {
					cout << " Ok\n";
				}
			}
		}
	}

	return retVal;
} <commit_msg>kernel:   * ITimeArithmetics: more tests, some code cleanup, tightened the secs<->float conversion tolerance.<commit_after>
#include <iostream>
#include <iomanip>

#include <openvibe/ovITimeArithmetics.h>

using namespace OpenViBE;
using namespace std;

int main(int argc, char *argv[])
{
	uint64 samplingRatesToTest[] = {100,128,200,400,512,1000};

	int retVal = 0;

	uint64 secsAndBackTolerance = {ITimeArithmetics::secondsToTime(0.001)};

	cout << "To seconds and back conversion tolerance has been set to " << ITimeArithmetics::timeToSeconds(secsAndBackTolerance) << " secs\n\n";

	{
		cout << "------\nTest: 'time to sample and back' using predefined times (given orig. as secs)\n------\n";

		uint64 timesToTest[] = {ITimeArithmetics::secondsToTime(0.0),
			ITimeArithmetics::secondsToTime(1.0),
			ITimeArithmetics::secondsToTime(1.5),
			ITimeArithmetics::secondsToTime(2.0),
			ITimeArithmetics::secondsToTime(100.0),
			ITimeArithmetics::secondsToTime(128.0)};

		cout << " " << setw(6) << "Rate"
			<< " " << setw(10) << "Sample"
			<< " " << setw(15) << "Time"
			<< " " << setw(15) << "TimeInv"
			<< " " << setw(5)  << "Secs"
			<< " " << setw(15) << "TimeInv2"
			<< " Tests\n";
		for(int i=0;i<sizeof(samplingRatesToTest)/sizeof(samplingRatesToTest[0]);i++) {
			for(int j=0;j<sizeof(timesToTest)/sizeof(timesToTest[0]);j++) {
				uint64 sampleIdx = ITimeArithmetics::timeToSampleIndex(samplingRatesToTest[i], timesToTest[j]);
				uint64 timeFromSample =  ITimeArithmetics::sampleIndexToTime(samplingRatesToTest[i], sampleIdx);
				float64 secondsFromTime = ITimeArithmetics::timeToSeconds(timesToTest[j]);
				uint64 timeFromSeconds = ITimeArithmetics::secondsToTime(secondsFromTime);
				cout << " " << setw(6) << samplingRatesToTest[i]
					<< " " << setw(10) << sampleIdx
					<< " " << setw(15) << timesToTest[j]
					<< " " << setw(15) << timeFromSample
					<< " " << setw(5)  << secondsFromTime
					<< " " << setw(15) << timeFromSeconds;
				boolean hadError = false;
				if(timeFromSample != timesToTest[j]) {
					cout << "  Error: Converting time to sample and back don't match\n";
					retVal |= 1;
					hadError = true;
				}
				if(std::abs((int64)timeFromSeconds - (int64)timesToTest[j]) > (int64) secsAndBackTolerance) {
					cout << "  Error: Converting time to seconds and back exceed tolerance\n";
					retVal |= 2;
					hadError = true;
				}
				if(!hadError) {
					cout << " Ok\n";
				}
			}
		}
	}

	{
		cout << "------\nTest: 'sample to time and back' using predefined samples\n------\n";

		uint64 samplesToTest[] = {0,1,100,128,512,1000,1021,1024};

		cout << " " << setw(6) << "Rate"
			<< " " << setw(10) << "Sample"
			<< " " << setw(15) << "SampleInv"
			<< " " << setw(15) << "Time"
			<< " " << setw(15) << "Secs"
			<< " " << setw(15) << "TimeInv2"
			<< " Tests\n";
		for(int i=0;i<sizeof(samplingRatesToTest)/sizeof(samplingRatesToTest[0]);i++) {
			for(int j=0;j<sizeof(samplesToTest)/sizeof(samplesToTest[0]);j++) {
				uint64 timeFromSample =  ITimeArithmetics::sampleIndexToTime(samplingRatesToTest[i], samplesToTest[j]);
				float64 secondsFromTime = ITimeArithmetics::timeToSeconds(timeFromSample);
				uint64 sampleFromTime =  ITimeArithmetics::timeToSampleIndex(samplingRatesToTest[i], timeFromSample);
				uint64 timeFromSeconds = ITimeArithmetics::secondsToTime(secondsFromTime);

				cout << " " << setw(6) << samplingRatesToTest[i]
					<< " " << setw(10) << samplesToTest[j]
					<< " " << setw(15) << sampleFromTime
					<< " " << setw(15) << timeFromSample
					<< " " << setw(15) << secondsFromTime
					<< " " << setw(15) << timeFromSeconds;
				boolean hadError = false;
				if(samplesToTest[j] != sampleFromTime) {
					cout << "  Error: Converting sample to time and back don't match\n";
					retVal |= 3;
					hadError = true;
				}
				if(std::abs((int64)timeFromSeconds - (int64)timeFromSample) > (int64)secsAndBackTolerance) {
					cout << "  Error: Converting time to seconds and back exceed tolerance\n";
					retVal |= 4;
					hadError = true;
				}
				if(!hadError) {
					cout << " Ok\n";
				}
			}
		}
	}

	{
		cout << "------\nTest: One second of signal at 'rate' should equal 'rate' samples\n------\n";

		cout << setw(6) << "Rate"
		     << setw(8) << "Samples"
			 << " Test\n";
		for(int i=0;i<sizeof(samplingRatesToTest)/sizeof(samplingRatesToTest[0]);i++) {
			uint64 nSamples = ITimeArithmetics::timeToSampleIndex(samplingRatesToTest[i], ITimeArithmetics::secondsToTime(1.0));
			cout << setw(6) << samplingRatesToTest[i]
			     << setw(8) << nSamples;
			if(nSamples == samplingRatesToTest[i]) {
				cout << " Ok\n";
			} else {
				cout << " Error\n";
				retVal |= 5;
			}
		}
	}

	return retVal;
} <|endoftext|>


<commit_before>/*
 * Copyright (C) 2013-2016 Alexander Saprykin <xelfium@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
 */

#ifndef PLIB_TESTS_STATIC
#  define BOOST_TEST_DYN_LINK
#endif

#define BOOST_TEST_MODULE plist_test

#include "plib.h"

#include <string.h>

#ifdef PLIB_TESTS_STATIC
#  include <boost/test/included/unit_test.hpp>
#else
#  include <boost/test/unit_test.hpp>
#endif

typedef struct _TestData {
	pint test_array[3];
	pint index;
} TestData;

static void foreach_test_func (ppointer data, ppointer user_data)
{
	if (user_data == NULL)
		return;

	TestData *test_data = (TestData *) user_data;

	if (test_data->index < 0 || test_data->index > 2)
		return;

	test_data->test_array[test_data->index] = P_POINTER_TO_INT (data);
	++test_data->index;
}

BOOST_AUTO_TEST_SUITE (BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE (plist_invalid_test)
{
	BOOST_CHECK (p_list_remove (NULL, NULL) == NULL);
	BOOST_CHECK (p_list_last (NULL) == NULL);
	BOOST_CHECK (p_list_length (NULL) == 0);
	BOOST_CHECK (p_list_reverse (NULL) == NULL);

	p_list_free (NULL);
	p_list_foreach (NULL, NULL, NULL);
}

BOOST_AUTO_TEST_CASE (plist_general_test)
{
	PList		*list = NULL;
	TestData	test_data;

	p_lib_init ();

	/* Testing append */
	list = p_list_append (list, P_INT_TO_POINTER (32));
	list = p_list_append (list, P_INT_TO_POINTER (64));

	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 2);

	/* Testing data access */
	BOOST_CHECK (P_POINTER_TO_INT (list->data) == 32);
	BOOST_CHECK (P_POINTER_TO_INT (p_list_last(list)->data) == 64);

	/* Testing prepend */
	list = p_list_prepend (list, P_INT_TO_POINTER (128));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 3);
	BOOST_CHECK (P_POINTER_TO_INT (list->data) == 128);
	BOOST_CHECK (P_POINTER_TO_INT (p_list_last(list)->data) == 64);

	/* Testing for each loop */
	memset (&test_data, 0, sizeof (test_data));

	BOOST_REQUIRE (test_data.test_array[0] == 0);
	BOOST_REQUIRE (test_data.test_array[1] == 0);
	BOOST_REQUIRE (test_data.test_array[2] == 0);
	BOOST_REQUIRE (test_data.index == 0);

	p_list_foreach (list, (PFunc) foreach_test_func, (ppointer) &test_data);

	BOOST_CHECK (test_data.index == 3);
	BOOST_CHECK (test_data.test_array[0] == 128);
	BOOST_CHECK (test_data.test_array[1] == 32);
	BOOST_CHECK (test_data.test_array[2] == 64);

	/* Testing reverse */

	list = p_list_reverse (list);

	BOOST_CHECK (list != NULL);
	BOOST_CHECK (p_list_length (list) == 3);
	BOOST_CHECK (P_POINTER_TO_INT (list->data) == 64);
	BOOST_CHECK (P_POINTER_TO_INT (p_list_last(list)->data) == 128);

	/* Testing for each loop */
	memset (&test_data, 0, sizeof (test_data));

	BOOST_REQUIRE (test_data.test_array[0] == 0);
	BOOST_REQUIRE (test_data.test_array[1] == 0);
	BOOST_REQUIRE (test_data.test_array[2] == 0);
	BOOST_REQUIRE (test_data.index == 0);

	p_list_foreach (list, (PFunc) foreach_test_func, (ppointer) &test_data);

	BOOST_CHECK (test_data.index == 3);
	BOOST_CHECK (test_data.test_array[0] == 64);
	BOOST_CHECK (test_data.test_array[1] == 32);
	BOOST_CHECK (test_data.test_array[2] == 128);

	/* Testing remove */
	list = p_list_remove (list, P_INT_TO_POINTER (32));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 2);

	list = p_list_remove (list, P_INT_TO_POINTER (128));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 1);

	list = p_list_remove (list, P_INT_TO_POINTER (256));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 1);

	list = p_list_remove (list, P_INT_TO_POINTER (64));
	BOOST_REQUIRE (list == NULL);
	BOOST_CHECK (p_list_length (list) == 0);

	p_list_free (list);

	p_lib_shutdown ();
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>tests: Forget library initialization routines in PList test<commit_after>/*
 * Copyright (C) 2013-2016 Alexander Saprykin <xelfium@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
 */

#ifndef PLIB_TESTS_STATIC
#  define BOOST_TEST_DYN_LINK
#endif

#define BOOST_TEST_MODULE plist_test

#include "plib.h"

#include <string.h>

#ifdef PLIB_TESTS_STATIC
#  include <boost/test/included/unit_test.hpp>
#else
#  include <boost/test/unit_test.hpp>
#endif

typedef struct _TestData {
	pint test_array[3];
	pint index;
} TestData;

static void foreach_test_func (ppointer data, ppointer user_data)
{
	if (user_data == NULL)
		return;

	TestData *test_data = (TestData *) user_data;

	if (test_data->index < 0 || test_data->index > 2)
		return;

	test_data->test_array[test_data->index] = P_POINTER_TO_INT (data);
	++test_data->index;
}

BOOST_AUTO_TEST_SUITE (BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE (plist_invalid_test)
{
	p_lib_init ();

	BOOST_CHECK (p_list_remove (NULL, NULL) == NULL);
	BOOST_CHECK (p_list_last (NULL) == NULL);
	BOOST_CHECK (p_list_length (NULL) == 0);
	BOOST_CHECK (p_list_reverse (NULL) == NULL);

	p_list_free (NULL);
	p_list_foreach (NULL, NULL, NULL);

	p_lib_shutdown ();
}

BOOST_AUTO_TEST_CASE (plist_general_test)
{
	PList		*list = NULL;
	TestData	test_data;

	p_lib_init ();

	/* Testing append */
	list = p_list_append (list, P_INT_TO_POINTER (32));
	list = p_list_append (list, P_INT_TO_POINTER (64));

	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 2);

	/* Testing data access */
	BOOST_CHECK (P_POINTER_TO_INT (list->data) == 32);
	BOOST_CHECK (P_POINTER_TO_INT (p_list_last(list)->data) == 64);

	/* Testing prepend */
	list = p_list_prepend (list, P_INT_TO_POINTER (128));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 3);
	BOOST_CHECK (P_POINTER_TO_INT (list->data) == 128);
	BOOST_CHECK (P_POINTER_TO_INT (p_list_last(list)->data) == 64);

	/* Testing for each loop */
	memset (&test_data, 0, sizeof (test_data));

	BOOST_REQUIRE (test_data.test_array[0] == 0);
	BOOST_REQUIRE (test_data.test_array[1] == 0);
	BOOST_REQUIRE (test_data.test_array[2] == 0);
	BOOST_REQUIRE (test_data.index == 0);

	p_list_foreach (list, (PFunc) foreach_test_func, (ppointer) &test_data);

	BOOST_CHECK (test_data.index == 3);
	BOOST_CHECK (test_data.test_array[0] == 128);
	BOOST_CHECK (test_data.test_array[1] == 32);
	BOOST_CHECK (test_data.test_array[2] == 64);

	/* Testing reverse */

	list = p_list_reverse (list);

	BOOST_CHECK (list != NULL);
	BOOST_CHECK (p_list_length (list) == 3);
	BOOST_CHECK (P_POINTER_TO_INT (list->data) == 64);
	BOOST_CHECK (P_POINTER_TO_INT (p_list_last(list)->data) == 128);

	/* Testing for each loop */
	memset (&test_data, 0, sizeof (test_data));

	BOOST_REQUIRE (test_data.test_array[0] == 0);
	BOOST_REQUIRE (test_data.test_array[1] == 0);
	BOOST_REQUIRE (test_data.test_array[2] == 0);
	BOOST_REQUIRE (test_data.index == 0);

	p_list_foreach (list, (PFunc) foreach_test_func, (ppointer) &test_data);

	BOOST_CHECK (test_data.index == 3);
	BOOST_CHECK (test_data.test_array[0] == 64);
	BOOST_CHECK (test_data.test_array[1] == 32);
	BOOST_CHECK (test_data.test_array[2] == 128);

	/* Testing remove */
	list = p_list_remove (list, P_INT_TO_POINTER (32));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 2);

	list = p_list_remove (list, P_INT_TO_POINTER (128));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 1);

	list = p_list_remove (list, P_INT_TO_POINTER (256));
	BOOST_REQUIRE (list != NULL);
	BOOST_CHECK (p_list_length (list) == 1);

	list = p_list_remove (list, P_INT_TO_POINTER (64));
	BOOST_REQUIRE (list == NULL);
	BOOST_CHECK (p_list_length (list) == 0);

	p_list_free (list);

	p_lib_shutdown ();
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: xmlencryption_mscryptimpl.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2004-11-26 14:58:21 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLENCRYPTION_MSCRYPTIMPL_HXX_
#define _XMLENCRYPTION_MSCRYPTIMPL_HXX_

#ifndef _SAL_CONFIG_H_
#include <sal/config.h>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _CPPUHELPER_FACTORY_HXX_
#include <cppuhelper/factory.hxx>
#endif

#ifndef _CPPUHELPER_IMPLBASE3_HXX_
#include <cppuhelper/implbase3.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_EXCEPTION_HPP_
#include <com/sun/star/uno/Exception.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HPP_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XSECVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XINITIALIZATION_HPP_
#include <com/sun/star/lang/XInitialization.hpp>
#endif

#ifndef _COM_SUN_STAR_XML_CRYPTO_XXMLENCRYPTION_HPP_
#include <com/sun/star/xml/crypto/XXMLEncryption.hpp>
#endif

#ifndef _COM_SUN_STAR_XML_CRYPTO_XXMLENCRYPTIONTEMPLATE_HPP_
#include <com/sun/star/xml/crypto/XXMLEncryptionTemplate.hpp>
#endif

#ifndef _COM_SUN_STAR_XML_CRYPTO_XXMLSECURITYCONTEXT_HPP_
#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
#endif

class XMLEncryption_MSCryptImpl : public ::cppu::WeakImplHelper3<
    ::com::sun::star::xml::crypto::XXMLEncryption ,
    ::com::sun::star::lang::XInitialization ,
    ::com::sun::star::lang::XServiceInfo >
{
    private :
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xServiceManager ;

    public :
        XMLEncryption_MSCryptImpl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& aFactory ) ;
        virtual ~XMLEncryption_MSCryptImpl() ;

        //Methods from XXMLEncryption
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate > SAL_CALL encrypt(
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate >& aTemplate ,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLSecurityContext >& aContext)
            // ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) ;
            throw ( com::sun::star::xml::crypto::XMLEncryptionException ,
                    com::sun::star::uno::SecurityException);

        virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate > SAL_CALL decrypt(
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate >& aTemplate ,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLSecurityContext >& aContext
        ) throw( com::sun::star::xml::crypto::XMLEncryptionException ,
                    com::sun::star::uno::SecurityException) ;

        //Methods from XInitialization
        virtual void SAL_CALL initialize(
            const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments
        ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) ;

        //Methods from XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ) ;

        virtual sal_Bool SAL_CALL supportsService(
            const ::rtl::OUString& ServiceName
        ) throw( ::com::sun::star::uno::RuntimeException ) ;

        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ) ;

        //Helper for XServiceInfo
        static ::com::sun::star::uno::Sequence< ::rtl::OUString > impl_getSupportedServiceNames() ;

        static ::rtl::OUString impl_getImplementationName() throw( ::com::sun::star::uno::RuntimeException ) ;

        //Helper for registry
        static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL impl_createInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& aServiceManager ) throw( ::com::sun::star::uno::RuntimeException ) ;

        static ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > impl_createFactory( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& aServiceManager ) ;
} ;

#endif  // _XMLENCRYPTION_MSCRYPTIMPL_HXX_

<commit_msg>INTEGRATION: CWS xmlsec08 (1.2.10); FILE MERGED 2005/01/20 03:34:25 mmi 1.2.10.1: smartcard support Issue number:  38448 Submitted by: Reviewed by:<commit_after>/*************************************************************************
 *
 *  $RCSfile: xmlencryption_mscryptimpl.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-10 18:11:13 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLENCRYPTION_MSCRYPTIMPL_HXX_
#define _XMLENCRYPTION_MSCRYPTIMPL_HXX_

#ifndef _SAL_CONFIG_H_
#include <sal/config.h>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _CPPUHELPER_FACTORY_HXX_
#include <cppuhelper/factory.hxx>
#endif

#ifndef _CPPUHELPER_IMPLBASE3_HXX_
#include <cppuhelper/implbase3.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_EXCEPTION_HPP_
#include <com/sun/star/uno/Exception.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HPP_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XSECVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XINITIALIZATION_HPP_
#include <com/sun/star/lang/XInitialization.hpp>
#endif

#ifndef _COM_SUN_STAR_XML_CRYPTO_XXMLENCRYPTION_HPP_
#include <com/sun/star/xml/crypto/XXMLEncryption.hpp>
#endif

#ifndef _COM_SUN_STAR_XML_CRYPTO_XXMLENCRYPTIONTEMPLATE_HPP_
#include <com/sun/star/xml/crypto/XXMLEncryptionTemplate.hpp>
#endif

#ifndef _COM_SUN_STAR_XML_CRYPTO_XXMLSECURITYCONTEXT_HPP_
#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
#endif

class XMLEncryption_MSCryptImpl : public ::cppu::WeakImplHelper3<
    ::com::sun::star::xml::crypto::XXMLEncryption ,
    ::com::sun::star::lang::XInitialization ,
    ::com::sun::star::lang::XServiceInfo >
{
    private :
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xServiceManager ;

    public :
        XMLEncryption_MSCryptImpl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& aFactory ) ;
        virtual ~XMLEncryption_MSCryptImpl() ;

        //Methods from XXMLEncryption
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate > SAL_CALL encrypt(
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate >& aTemplate ,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment >& aEnvironment)
            // ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) ;
            throw ( com::sun::star::xml::crypto::XMLEncryptionException ,
                    com::sun::star::uno::SecurityException);

        virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate > SAL_CALL decrypt(
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLEncryptionTemplate >& aTemplate ,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XXMLSecurityContext >& aContext
        ) throw( com::sun::star::xml::crypto::XMLEncryptionException ,
                    com::sun::star::uno::SecurityException) ;

        //Methods from XInitialization
        virtual void SAL_CALL initialize(
            const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments
        ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) ;

        //Methods from XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ) ;

        virtual sal_Bool SAL_CALL supportsService(
            const ::rtl::OUString& ServiceName
        ) throw( ::com::sun::star::uno::RuntimeException ) ;

        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ) ;

        //Helper for XServiceInfo
        static ::com::sun::star::uno::Sequence< ::rtl::OUString > impl_getSupportedServiceNames() ;

        static ::rtl::OUString impl_getImplementationName() throw( ::com::sun::star::uno::RuntimeException ) ;

        //Helper for registry
        static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL impl_createInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& aServiceManager ) throw( ::com::sun::star::uno::RuntimeException ) ;

        static ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > impl_createFactory( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& aServiceManager ) ;
} ;

#endif  // _XMLENCRYPTION_MSCRYPTIMPL_HXX_

<|endoftext|>


<commit_before>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "transactionrecord.h"

#include "base58.h"
#include "consensus/consensus.h"
#include "main.h"
#include "timedata.h"
#include "wallet/wallet.h"

#include <stdint.h>

#include <boost/foreach.hpp>

/* Return positive answer if transaction should be shown in list.
 */
bool TransactionRecord::showTransaction(const CWalletTx &wtx)
{
    if (wtx.IsCoinBase())
    {
        // Ensures we show generated coins / mined transactions at depth 1
        if (!wtx.IsInMainChain())
        {
            return false;
        }
    }
    return true;
}

/*
 * Decompose CWallet transaction to model transaction records.
 */
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
{
    QList<TransactionRecord> parts;
    int64_t nTime = wtx.GetTxTime();
    CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
    CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
    CAmount nNet = nCredit - nDebit;
    uint256 hash = wtx.GetHash();
    std::map<std::string, std::string> mapValue = wtx.mapValue;

    if(wtx.IsZerocoinSpend() || wtx.IsZerocoinSpendV3())
    {
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        {
            isminetype mine = wallet->IsMine(txout);

            TransactionRecord sub(hash, nTime);
            CTxDestination address;

            sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
            if(mine)
            {
                if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                {
                    sub.type = TransactionRecord::SpendToSelf;
                    sub.address = CBitcoinAddress(address).ToString();
                }
            }
            else if(ExtractDestination(txout.scriptPubKey, address))
            {
                sub.type = TransactionRecord::SpendToAddress;
                sub.address = CBitcoinAddress(address).ToString();
            }
            parts.append(sub);
        }
    }
    else if(wtx.IsZerocoinMint() || wtx.IsZerocoinMintV3())
    {
        TransactionRecord sub(hash, nTime);
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
        {
            sub.type = TransactionRecord::Mint;
            parts.append(sub);
        }
    }
    else if (nNet > 0 || wtx.IsCoinBase())
    {
        //
        // Credit
        //
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        {
            isminetype mine = wallet->IsMine(txout);
            if(mine)
            {
                TransactionRecord sub(hash, nTime);
                CTxDestination address;
                sub.idx = parts.size(); // sequence number
                sub.credit = txout.nValue;
                sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
                if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                {
                    // Received by Bitcoin Address
                    sub.type = TransactionRecord::RecvWithAddress;
                    sub.address = CBitcoinAddress(address).ToString();
                }
                else
                {
                    // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
                    sub.type = TransactionRecord::RecvFromOther;
                     sub.address = mapValue["from"];
                }
                if (wtx.IsCoinBase())
                {
                    // Generated
                    sub.type = TransactionRecord::Generated;
                }

                parts.append(sub);
            }
        }
    }
    else
    {
        bool involvesWatchAddress = false;
        isminetype fAllFromMe = ISMINE_SPENDABLE;
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
        {
            isminetype mine = wallet->IsMine(txin);
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllFromMe > mine) fAllFromMe = mine;
        }

        isminetype fAllToMe = ISMINE_SPENDABLE;
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        {
            isminetype mine = wallet->IsMine(txout);
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllToMe > mine) fAllToMe = mine;
        }

        if (fAllFromMe && fAllToMe)
        {
            // Payment to self
            CAmount nChange = wtx.GetChange();

            parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
                            -(nDebit - nChange), nCredit - nChange));
            parts.last().involvesWatchAddress = involvesWatchAddress;   // maybe pass to TransactionRecord as constructor argument
        }
        else if (fAllFromMe)
        {
            //
            // Debit
            //
            CAmount nTxFee = nDebit - wtx.GetValueOut();

            for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
            {
                const CTxOut& txout = wtx.vout[nOut];
                TransactionRecord sub(hash, nTime);
                sub.idx = parts.size();
                sub.involvesWatchAddress = involvesWatchAddress;

                if(wallet->IsMine(txout))
                {
                    // Ignore parts sent to self, as this is usually the change
                    // from a transaction sent back to our own address.
                    continue;
                }

                CTxDestination address;
                if (ExtractDestination(txout.scriptPubKey, address))
                {
                    // Sent to Bitcoin Address
                    sub.type = TransactionRecord::SendToAddress;
                    sub.address = CBitcoinAddress(address).ToString();
                }
                else
                {
                    // Sent to IP, or other non-address transaction like OP_EVAL
                    sub.type = TransactionRecord::SendToOther;
                    sub.address = mapValue["to"];
                }

                CAmount nValue = txout.nValue;
                /* Add fee to first output */
                if (nTxFee > 0)
                {
                    nValue += nTxFee;
                    nTxFee = 0;
                }
                sub.debit = -nValue;

                parts.append(sub);
            }
        }
        else
        {
            //
            // Mixed debit transaction, can't break down payees
            //
            parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
            parts.last().involvesWatchAddress = involvesWatchAddress;
        }
    }

    return parts;
}

void TransactionRecord::updateStatus(const CWalletTx &wtx)
{
    AssertLockHeld(cs_main);
    // Determine transaction status

    // Find the block the tx is in
    CBlockIndex* pindex = NULL;
    BlockMap::iterator mi = mapBlockIndex.find(wtx.hashBlock);
    if (mi != mapBlockIndex.end())
        pindex = (*mi).second;

    // Sort order, unrecorded transactions sort to the top
    status.sortKey = strprintf("%010d-%01d-%010u-%03d",
        (pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
        (wtx.IsCoinBase() ? 1 : 0),
        wtx.nTimeReceived,
        idx);
    status.countsForBalance = wtx.IsTrusted() && !(wtx.GetBlocksToMaturity() > 0);
    status.depth = wtx.GetDepthInMainChain();
    status.cur_num_blocks = chainActive.Height();

    if (!CheckFinalTx(wtx))
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
        {
            status.status = TransactionStatus::OpenUntilBlock;
            status.open_for = wtx.nLockTime - chainActive.Height();
        }
        else
        {
            status.status = TransactionStatus::OpenUntilDate;
            status.open_for = wtx.nLockTime;
        }
    }
    // For generated transactions, determine maturity
    else if(type == TransactionRecord::Generated)
    {
        if (wtx.GetBlocksToMaturity() > 0)
        {
            status.status = TransactionStatus::Immature;

            if (wtx.IsInMainChain())
            {
                status.matures_in = wtx.GetBlocksToMaturity();

                // Check if the block was requested by anyone
                if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
                    status.status = TransactionStatus::MaturesWarning;
            }
            else
            {
                status.status = TransactionStatus::NotAccepted;
            }
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }
    else
    {
        if (status.depth < 0)
        {
            status.status = TransactionStatus::Conflicted;
        }
        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
        {
            status.status = TransactionStatus::Offline;
        }
        else if (status.depth == 0)
        {
            status.status = TransactionStatus::Unconfirmed;
            if (wtx.isAbandoned())
                status.status = TransactionStatus::Abandoned;
        }
        else if (status.depth < RecommendedNumConfirmations)
        {
            status.status = TransactionStatus::Confirming;
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }

}

bool TransactionRecord::statusUpdateNeeded()
{
    AssertLockHeld(cs_main);
    return status.cur_num_blocks != chainActive.Height();
}

QString TransactionRecord::getTxID() const
{
    return QString::fromStdString(hash.ToString());
}

int TransactionRecord::getOutputIndex() const
{
    return idx;
}
<commit_msg>Optimized code, fixed mint/spend amount view<commit_after>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "transactionrecord.h"

#include "base58.h"
#include "consensus/consensus.h"
#include "main.h"
#include "timedata.h"
#include "wallet/wallet.h"

#include <stdint.h>

#include <boost/foreach.hpp>

/* Return positive answer if transaction should be shown in list.
 */
bool TransactionRecord::showTransaction(const CWalletTx &wtx)
{
    if (wtx.IsCoinBase())
    {
        // Ensures we show generated coins / mined transactions at depth 1
        if (!wtx.IsInMainChain())
        {
            return false;
        }
    }
    return true;
}

/*
 * Decompose CWallet transaction to model transaction records.
 */
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
{
    QList<TransactionRecord> parts;
    int64_t nTime = wtx.GetTxTime();
    CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
    CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
    CAmount nNet = nCredit - nDebit;
    uint256 hash = wtx.GetHash();
    std::map<std::string, std::string> mapValue = wtx.mapValue;

    if (nNet > 0 || wtx.IsCoinBase() ||
        wtx.IsZerocoinSpend() || wtx.IsZerocoinSpendV3())
    {
        //
        // Credit
        //
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        {
            isminetype mine = wallet->IsMine(txout);

            TransactionRecord sub(hash, nTime);
            CTxDestination address;
            sub.idx = parts.size(); // sequence number
            sub.credit = txout.nValue;

            if(wtx.IsZerocoinSpend() || wtx.IsZerocoinSpendV3())
            {
                if (mine)
                {
                    sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
                    if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                    {
                        sub.type = TransactionRecord::SpendToSelf;
                        sub.address = CBitcoinAddress(address).ToString();
                    }
                }
                else
                {
                    ExtractDestination(txout.scriptPubKey, address);
                    sub.type = TransactionRecord::SpendToAddress;
                    sub.address = CBitcoinAddress(address).ToString();
                }
            }
            else if(mine)
            {
                sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
                if(ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                {
                    // Received by Bitcoin Address
                    sub.type = TransactionRecord::RecvWithAddress;
                    sub.address = CBitcoinAddress(address).ToString();
                }
                else
                {
                    // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
                    sub.type = TransactionRecord::RecvFromOther;
                    sub.address = mapValue["from"];
                }
                if (wtx.IsCoinBase())
                {
                    // Generated
                    sub.type = TransactionRecord::Generated;
                }
            }
            parts.append(sub);
        }
    }
    else
    {
        bool involvesWatchAddress = false;
        isminetype fAllFromMe = ISMINE_SPENDABLE;
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
        {
            isminetype mine = wallet->IsMine(txin);
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllFromMe > mine) fAllFromMe = mine;
        }

        isminetype fAllToMe = ISMINE_SPENDABLE;
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        {
            isminetype mine = wallet->IsMine(txout);
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllToMe > mine) fAllToMe = mine;
        }

        if (fAllFromMe && fAllToMe)
        {
            // Payment to self
            CAmount nChange = wtx.GetChange();

            parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
                            -(nDebit - nChange), nCredit - nChange));
            parts.last().involvesWatchAddress = involvesWatchAddress;   // maybe pass to TransactionRecord as constructor argument
        }
        else if (fAllFromMe)
        {
            //
            // Debit
            //
            CAmount nTxFee = nDebit - wtx.GetValueOut();

            for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
            {
                const CTxOut& txout = wtx.vout[nOut];
                TransactionRecord sub(hash, nTime);
                sub.idx = parts.size();
                sub.involvesWatchAddress = involvesWatchAddress;

                if(wallet->IsMine(txout))
                {
                    // Ignore parts sent to self, as this is usually the change
                    // from a transaction sent back to our own address.
                    continue;
                }

                CTxDestination address;
                if (ExtractDestination(txout.scriptPubKey, address))
                {
                    // Sent to Bitcoin Address
                    sub.type = TransactionRecord::SendToAddress;
                    sub.address = CBitcoinAddress(address).ToString();
                }
                else if(wtx.IsZerocoinMint() || wtx.IsZerocoinMintV3())
                {
                    sub.type = TransactionRecord::Mint;
                }
                else
                {
                    // Sent to IP, or other non-address transaction like OP_EVAL
                    sub.type = TransactionRecord::SendToOther;
                    sub.address = mapValue["to"];
                }

                CAmount nValue = txout.nValue;
                /* Add fee to first output */
                if (nTxFee > 0)
                {
                    nValue += nTxFee;
                    nTxFee = 0;
                }
                sub.debit = -nValue;

                parts.append(sub);
            }
        }
        else
        {
            //
            // Mixed debit transaction, can't break down payees
            //
            parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
            parts.last().involvesWatchAddress = involvesWatchAddress;
        }
    }

    return parts;
}

void TransactionRecord::updateStatus(const CWalletTx &wtx)
{
    AssertLockHeld(cs_main);
    // Determine transaction status

    // Find the block the tx is in
    CBlockIndex* pindex = NULL;
    BlockMap::iterator mi = mapBlockIndex.find(wtx.hashBlock);
    if (mi != mapBlockIndex.end())
        pindex = (*mi).second;

    // Sort order, unrecorded transactions sort to the top
    status.sortKey = strprintf("%010d-%01d-%010u-%03d",
        (pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
        (wtx.IsCoinBase() ? 1 : 0),
        wtx.nTimeReceived,
        idx);
    status.countsForBalance = wtx.IsTrusted() && !(wtx.GetBlocksToMaturity() > 0);
    status.depth = wtx.GetDepthInMainChain();
    status.cur_num_blocks = chainActive.Height();

    if (!CheckFinalTx(wtx))
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
        {
            status.status = TransactionStatus::OpenUntilBlock;
            status.open_for = wtx.nLockTime - chainActive.Height();
        }
        else
        {
            status.status = TransactionStatus::OpenUntilDate;
            status.open_for = wtx.nLockTime;
        }
    }
    // For generated transactions, determine maturity
    else if(type == TransactionRecord::Generated)
    {
        if (wtx.GetBlocksToMaturity() > 0)
        {
            status.status = TransactionStatus::Immature;

            if (wtx.IsInMainChain())
            {
                status.matures_in = wtx.GetBlocksToMaturity();

                // Check if the block was requested by anyone
                if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
                    status.status = TransactionStatus::MaturesWarning;
            }
            else
            {
                status.status = TransactionStatus::NotAccepted;
            }
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }
    else
    {
        if (status.depth < 0)
        {
            status.status = TransactionStatus::Conflicted;
        }
        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
        {
            status.status = TransactionStatus::Offline;
        }
        else if (status.depth == 0)
        {
            status.status = TransactionStatus::Unconfirmed;
            if (wtx.isAbandoned())
                status.status = TransactionStatus::Abandoned;
        }
        else if (status.depth < RecommendedNumConfirmations)
        {
            status.status = TransactionStatus::Confirming;
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }

}

bool TransactionRecord::statusUpdateNeeded()
{
    AssertLockHeld(cs_main);
    return status.cur_num_blocks != chainActive.Height();
}

QString TransactionRecord::getTxID() const
{
    return QString::fromStdString(hash.ToString());
}

int TransactionRecord::getOutputIndex() const
{
    return idx;
}
<|endoftext|>


<commit_before>// Copyright 2010-2013 RethinkDB, all rights reserved.

#include "rdb_protocol/batching.hpp"

#include "rdb_protocol/datum.hpp"
#include "rdb_protocol/env.hpp"
#include "rdb_protocol/error.hpp"

namespace ql {

static const int64_t DEFAULT_MIN_ELS = 8;
static const int64_t DEFAULT_FIRST_SCALEDOWN = 4;
static const int64_t DEFAULT_MAX_SIZE = MEGABYTE;
// The maximum duration of a batch in microseconds.
static const int64_t DEFAULT_MAX_DURATION = 500 * 1000;
// These numbers are sort of arbitrary, but they seem to work. See `scale_down()`
// for an explanation.
static const int64_t DIVISOR_SCALING_FACTOR = 8;
static const int64_t SCALE_CONSTANT = 8;

RDB_IMPL_SERIALIZABLE_7(batchspec_t,
                        batch_type,
                        min_els,
                        max_els,
                        max_size,
                        first_scaledown_factor,
                        max_dur,
                        start_time);
INSTANTIATE_SERIALIZABLE_FOR_CLUSTER(batchspec_t);

batchspec_t::batchspec_t(
    batch_type_t _batch_type,
    int64_t _min_els,
    int64_t _max_els,
    int64_t _max_size,
    int64_t _first_scaledown,
    int64_t _max_dur,
    microtime_t _start_time)
    : batch_type(_batch_type),
      min_els(_min_els),
      max_els(_max_els),
      max_size(_max_size),
      first_scaledown_factor(_first_scaledown),
      max_dur(_max_dur),
      start_time(_start_time) {
    r_sanity_check(first_scaledown_factor >= 1);
    r_sanity_check(max_els >= 1);
    r_sanity_check(min_els >= 1);
    r_sanity_check(max_els >= min_els);
    r_sanity_check(max_size >= 1);
    r_sanity_check(max_dur >= 0);
}

batchspec_t batchspec_t::user(batch_type_t batch_type,
                              const counted_t<const datum_t> &conf) {
    counted_t<const datum_t> max_els_d, min_els_d, max_size_d, max_dur_d;
    counted_t<const datum_t> first_scaledown_d;
    if (conf.has()) {
        min_els_d = conf->get("min_els", NOTHROW);
        max_els_d = conf->get("max_els", NOTHROW);
        max_size_d = conf->get("max_size", NOTHROW);
        first_scaledown_d = conf->get("first_scaledown", NOTHROW);
        max_dur_d = conf->get("max_dur", NOTHROW);
    }
    int64_t max_els = max_els_d.has()
                      ? max_els_d->as_int()
                      : std::numeric_limits<decltype(batchspec_t().max_els)>::max();
    int64_t min_els = min_els_d.has()
                      ? min_els_d->as_int()
                      : std::min<int64_t>(max_els, DEFAULT_MIN_ELS);
    int64_t max_size = max_size_d.has() ? max_size_d->as_int() : DEFAULT_MAX_SIZE;
    int64_t first_sd = first_scaledown_d.has()
                       ? first_scaledown_d->as_int()
                       : DEFAULT_FIRST_SCALEDOWN;
    int64_t max_dur = max_dur_d.has() ? max_dur_d->as_int() : DEFAULT_MAX_DURATION;
    return batchspec_t(batch_type,
                       min_els,
                       max_els,
                       max_size,
                       first_sd,
                       max_dur,
                       current_microtime());
}

batchspec_t batchspec_t::all() {
    return batchspec_t(batch_type_t::TERMINAL,
                       DEFAULT_MIN_ELS,
                       std::numeric_limits<decltype(batchspec_t().max_els)>::max(),
                       std::numeric_limits<decltype(batchspec_t().max_size)>::max(),
                       1,
                       0,
                       current_microtime());
}

batchspec_t batchspec_t::user(batch_type_t batch_type, env_t *env) {
    counted_t<val_t> v = env->global_optargs.get_optarg(env, "batch_conf");
    return user(batch_type, v.has() ? v->as_datum() : counted_t<const datum_t>());
}

batchspec_t batchspec_t::with_new_batch_type(batch_type_t new_batch_type) const {
    return batchspec_t(new_batch_type, min_els, max_els, max_size,
                       first_scaledown_factor, max_dur, start_time);
}

batchspec_t batchspec_t::with_at_most(uint64_t _max_els) const {
    // Special case: if _max_els is 1, we want min_els to also be 1 for maximum
    // efficiency.
    // If _max_els on the other hand is > 1 but still small, having
    // min_els = _max_els could result in multiple round-trips, since our unsharding
    // code would throw out a lot of documents. So in that case we just keep min_els
    // unchanged (and in fact elevate _max_els to min_els if _max_els < min_els
    // otherwise).
    int64_t new_min_els = _max_els == 1 ? 1 : min_els;
    int64_t new_max_els = std::max<int64_t>(new_min_els,
            std::min(uint64_t(std::numeric_limits<int64_t>::max()), _max_els));
    return batchspec_t(
        batch_type,
        new_min_els,
        new_max_els,
        max_size,
        first_scaledown_factor,
        max_dur,
        start_time);
}

batchspec_t batchspec_t::scale_down(int64_t divisor) const {
    // We divide by e.g. 7/8th of the divisor (assuming DIVISOR_SCALING_FACTOR == 8)
    // and add SCALE_CONSTANT to reduce the chances of needing a second round-trip
    // (we add a constant because unequal division is more likely with very small
    // sizes).  Law of large numbers says that the chances of needing a second
    // round-trip for large, non-pathological datasets are extremely low.
    int64_t new_max_els =
        max_els == std::numeric_limits<decltype(batchspec_t().max_els)>::max()
            ? max_els
            : std::min(max_els, (max_els * DIVISOR_SCALING_FACTOR
                                 / ((DIVISOR_SCALING_FACTOR - 1) * divisor))
                                + SCALE_CONSTANT);
    int64_t new_max_size =
        max_size == std::numeric_limits<decltype(batchspec_t().max_size)>::max()
            ? max_size
            : std::min(max_size, (max_size * DIVISOR_SCALING_FACTOR
                                  / ((DIVISOR_SCALING_FACTOR - 1) * divisor))
                                 + SCALE_CONSTANT);
    // to avoid problems when the batches get really tiny, we clamp new_max_els to be at least min_els.
    new_max_els = std::max(min_els, new_max_els);

    return batchspec_t(batch_type, min_els, new_max_els, new_max_size,
                       first_scaledown_factor, max_dur, start_time);
}

batcher_t batchspec_t::to_batcher() const {
    int64_t real_min_els =
        batch_type != batch_type_t::NORMAL_FIRST
            ? min_els
            : std::max<int64_t>(1, min_els / first_scaledown_factor);
    int64_t real_max_els =
        max_els == std::numeric_limits<decltype(batchspec_t().max_els)>::max()
        || batch_type != batch_type_t::NORMAL_FIRST
            ? max_els
            : std::max<int64_t>(1, max_els / first_scaledown_factor);
    int64_t real_max_size =
        max_size == std::numeric_limits<decltype(batchspec_t().max_size)>::max()
        || batch_type != batch_type_t::NORMAL_FIRST
            ? max_size
            : std::max<int64_t>(1, max_size / first_scaledown_factor);
    microtime_t cur_time = current_microtime();
    microtime_t end_time;
    if (batch_type == batch_type_t::NORMAL) {
        end_time = std::max(cur_time + (cur_time - start_time), start_time + max_dur);
    } else if (batch_type == batch_type_t::NORMAL_FIRST) {
        end_time = std::max(start_time + (max_dur / first_scaledown_factor),
                            cur_time + (max_dur / (first_scaledown_factor * 2)));
    } else {
        end_time = std::numeric_limits<decltype(end_time)>::max();
    }
    return batcher_t(batch_type, real_min_els, real_max_els, real_max_size, end_time);
}

bool batcher_t::should_send_batch() const {
    // We ignore size_left as long as we have not got at least `min_wanted_els`
    // documents.
    return els_left <= 0
        || (size_left <= 0 && min_els_left <= 0)
        || (current_microtime() >= end_time && seen_one_el);
}

batcher_t::batcher_t(
    batch_type_t _batch_type,
    int64_t min_els,
    int64_t max_els,
    int64_t max_size,
    microtime_t _end_time)
    : batch_type(_batch_type),
      seen_one_el(false),
      min_els_left(min_els),
      els_left(max_els),
      size_left(max_size),
      end_time(_end_time) { }

} // namespace ql
<commit_msg>Clamp min_els to max_els to prevent user dorkage from crashing server<commit_after>// Copyright 2010-2013 RethinkDB, all rights reserved.

#include "rdb_protocol/batching.hpp"

#include "rdb_protocol/datum.hpp"
#include "rdb_protocol/env.hpp"
#include "rdb_protocol/error.hpp"

namespace ql {

static const int64_t DEFAULT_MIN_ELS = 8;
static const int64_t DEFAULT_FIRST_SCALEDOWN = 4;
static const int64_t DEFAULT_MAX_SIZE = MEGABYTE;
// The maximum duration of a batch in microseconds.
static const int64_t DEFAULT_MAX_DURATION = 500 * 1000;
// These numbers are sort of arbitrary, but they seem to work. See `scale_down()`
// for an explanation.
static const int64_t DIVISOR_SCALING_FACTOR = 8;
static const int64_t SCALE_CONSTANT = 8;

RDB_IMPL_SERIALIZABLE_7(batchspec_t,
                        batch_type,
                        min_els,
                        max_els,
                        max_size,
                        first_scaledown_factor,
                        max_dur,
                        start_time);
INSTANTIATE_SERIALIZABLE_FOR_CLUSTER(batchspec_t);

batchspec_t::batchspec_t(
    batch_type_t _batch_type,
    int64_t _min_els,
    int64_t _max_els,
    int64_t _max_size,
    int64_t _first_scaledown,
    int64_t _max_dur,
    microtime_t _start_time)
    : batch_type(_batch_type),
      min_els(_min_els),
      max_els(_max_els),
      max_size(_max_size),
      first_scaledown_factor(_first_scaledown),
      max_dur(_max_dur),
      start_time(_start_time) {
    r_sanity_check(first_scaledown_factor >= 1);
    r_sanity_check(max_els >= 1);
    r_sanity_check(min_els >= 1);
    r_sanity_check(max_els >= min_els);
    r_sanity_check(max_size >= 1);
    r_sanity_check(max_dur >= 0);
}

batchspec_t batchspec_t::user(batch_type_t batch_type,
                              const counted_t<const datum_t> &conf) {
    counted_t<const datum_t> max_els_d, min_els_d, max_size_d, max_dur_d;
    counted_t<const datum_t> first_scaledown_d;
    if (conf.has()) {
        min_els_d = conf->get("min_els", NOTHROW);
        max_els_d = conf->get("max_els", NOTHROW);
        max_size_d = conf->get("max_size", NOTHROW);
        first_scaledown_d = conf->get("first_scaledown", NOTHROW);
        max_dur_d = conf->get("max_dur", NOTHROW);
    }
    int64_t max_els = max_els_d.has()
                      ? max_els_d->as_int()
                      : std::numeric_limits<decltype(batchspec_t().max_els)>::max();
    int64_t min_els = min_els_d.has()
                      ? min_els_d->as_int()
                      : std::min<int64_t>(max_els, DEFAULT_MIN_ELS);
    int64_t max_size = max_size_d.has() ? max_size_d->as_int() : DEFAULT_MAX_SIZE;
    int64_t first_sd = first_scaledown_d.has()
                       ? first_scaledown_d->as_int()
                       : DEFAULT_FIRST_SCALEDOWN;
    int64_t max_dur = max_dur_d.has() ? max_dur_d->as_int() : DEFAULT_MAX_DURATION;
    // Protect the user in case they're a dork.  Normally we would do rfail and
    // trigger exceptions, but due to NOTHROWs above this may not be safe.
    min_els = std::min<int64_t>(min_els, max_els);
    return batchspec_t(batch_type,
                       min_els,
                       max_els,
                       max_size,
                       first_sd,
                       max_dur,
                       current_microtime());
}

batchspec_t batchspec_t::all() {
    return batchspec_t(batch_type_t::TERMINAL,
                       DEFAULT_MIN_ELS,
                       std::numeric_limits<decltype(batchspec_t().max_els)>::max(),
                       std::numeric_limits<decltype(batchspec_t().max_size)>::max(),
                       1,
                       0,
                       current_microtime());
}

batchspec_t batchspec_t::user(batch_type_t batch_type, env_t *env) {
    counted_t<val_t> v = env->global_optargs.get_optarg(env, "batch_conf");
    return user(batch_type, v.has() ? v->as_datum() : counted_t<const datum_t>());
}

batchspec_t batchspec_t::with_new_batch_type(batch_type_t new_batch_type) const {
    return batchspec_t(new_batch_type, min_els, max_els, max_size,
                       first_scaledown_factor, max_dur, start_time);
}

batchspec_t batchspec_t::with_at_most(uint64_t _max_els) const {
    // Special case: if _max_els is 1, we want min_els to also be 1 for maximum
    // efficiency.
    // If _max_els on the other hand is > 1 but still small, having
    // min_els = _max_els could result in multiple round-trips, since our unsharding
    // code would throw out a lot of documents. So in that case we just keep min_els
    // unchanged (and in fact elevate _max_els to min_els if _max_els < min_els
    // otherwise).
    int64_t new_min_els = _max_els == 1 ? 1 : min_els;
    int64_t new_max_els = std::max<int64_t>(new_min_els,
            std::min(uint64_t(std::numeric_limits<int64_t>::max()), _max_els));
    return batchspec_t(
        batch_type,
        new_min_els,
        new_max_els,
        max_size,
        first_scaledown_factor,
        max_dur,
        start_time);
}

batchspec_t batchspec_t::scale_down(int64_t divisor) const {
    // We divide by e.g. 7/8th of the divisor (assuming DIVISOR_SCALING_FACTOR == 8)
    // and add SCALE_CONSTANT to reduce the chances of needing a second round-trip
    // (we add a constant because unequal division is more likely with very small
    // sizes).  Law of large numbers says that the chances of needing a second
    // round-trip for large, non-pathological datasets are extremely low.
    int64_t new_max_els =
        max_els == std::numeric_limits<decltype(batchspec_t().max_els)>::max()
            ? max_els
            : std::min(max_els, (max_els * DIVISOR_SCALING_FACTOR
                                 / ((DIVISOR_SCALING_FACTOR - 1) * divisor))
                                + SCALE_CONSTANT);
    int64_t new_max_size =
        max_size == std::numeric_limits<decltype(batchspec_t().max_size)>::max()
            ? max_size
            : std::min(max_size, (max_size * DIVISOR_SCALING_FACTOR
                                  / ((DIVISOR_SCALING_FACTOR - 1) * divisor))
                                 + SCALE_CONSTANT);
    // to avoid problems when the batches get really tiny, we clamp new_max_els to be at least min_els.
    new_max_els = std::max(min_els, new_max_els);

    return batchspec_t(batch_type, min_els, new_max_els, new_max_size,
                       first_scaledown_factor, max_dur, start_time);
}

batcher_t batchspec_t::to_batcher() const {
    int64_t real_min_els =
        batch_type != batch_type_t::NORMAL_FIRST
            ? min_els
            : std::max<int64_t>(1, min_els / first_scaledown_factor);
    int64_t real_max_els =
        max_els == std::numeric_limits<decltype(batchspec_t().max_els)>::max()
        || batch_type != batch_type_t::NORMAL_FIRST
            ? max_els
            : std::max<int64_t>(1, max_els / first_scaledown_factor);
    int64_t real_max_size =
        max_size == std::numeric_limits<decltype(batchspec_t().max_size)>::max()
        || batch_type != batch_type_t::NORMAL_FIRST
            ? max_size
            : std::max<int64_t>(1, max_size / first_scaledown_factor);
    microtime_t cur_time = current_microtime();
    microtime_t end_time;
    if (batch_type == batch_type_t::NORMAL) {
        end_time = std::max(cur_time + (cur_time - start_time), start_time + max_dur);
    } else if (batch_type == batch_type_t::NORMAL_FIRST) {
        end_time = std::max(start_time + (max_dur / first_scaledown_factor),
                            cur_time + (max_dur / (first_scaledown_factor * 2)));
    } else {
        end_time = std::numeric_limits<decltype(end_time)>::max();
    }
    return batcher_t(batch_type, real_min_els, real_max_els, real_max_size, end_time);
}

bool batcher_t::should_send_batch() const {
    // We ignore size_left as long as we have not got at least `min_wanted_els`
    // documents.
    return els_left <= 0
        || (size_left <= 0 && min_els_left <= 0)
        || (current_microtime() >= end_time && seen_one_el);
}

batcher_t::batcher_t(
    batch_type_t _batch_type,
    int64_t min_els,
    int64_t max_els,
    int64_t max_size,
    microtime_t _end_time)
    : batch_type(_batch_type),
      seen_one_el(false),
      min_els_left(min_els),
      els_left(max_els),
      size_left(max_size),
      end_time(_end_time) { }

} // namespace ql
<|endoftext|>


<commit_before>/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Solidity abstract syntax tree.
 */

#include <algorithm>

#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/Exceptions.h>

using namespace std;

namespace dev
{
namespace solidity
{

void ContractDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		listAccept(m_definedStructs, _visitor);
		listAccept(m_stateVariables, _visitor);
		listAccept(m_definedFunctions, _visitor);
	}
	_visitor.endVisit(*this);
}

void StructDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		listAccept(m_members, _visitor);
	_visitor.endVisit(*this);
}

void ParameterList::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		listAccept(m_parameters, _visitor);
	_visitor.endVisit(*this);
}

void FunctionDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_parameters->accept(_visitor);
		if (m_returnParameters)
			m_returnParameters->accept(_visitor);
		m_body->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void VariableDeclaration::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		if (m_typeName)
			m_typeName->accept(_visitor);
	_visitor.endVisit(*this);
}

void TypeName::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void ElementaryTypeName::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void UserDefinedTypeName::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Mapping::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_keyType->accept(_visitor);
		m_valueType->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Statement::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Block::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		listAccept(m_statements, _visitor);
	_visitor.endVisit(*this);
}

void IfStatement::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_condition->accept(_visitor);
		m_trueBody->accept(_visitor);
		if (m_falseBody)
			m_falseBody->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void BreakableStatement::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void WhileStatement::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_condition->accept(_visitor);
		m_body->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Continue::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Break::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Return::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		if (m_expression)
			m_expression->accept(_visitor);
	_visitor.endVisit(*this);
}

void VariableDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_variable->accept(_visitor);
		if (m_value)
			m_value->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Assignment::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_leftHandSide->accept(_visitor);
		m_rightHandSide->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void UnaryOperation::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		m_subExpression->accept(_visitor);
	_visitor.endVisit(*this);
}

void BinaryOperation::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_left->accept(_visitor);
		m_right->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void FunctionCall::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_expression->accept(_visitor);
		listAccept(m_arguments, _visitor);
	}
	_visitor.endVisit(*this);
}

void MemberAccess::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		m_expression->accept(_visitor);
	_visitor.endVisit(*this);
}

void IndexAccess::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_base->accept(_visitor);
		m_index->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Identifier::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Literal::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

TypeError ASTNode::createTypeError(string const& _description)
{
	return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
}

void Statement::expectType(Expression& _expression, const Type& _expectedType)
{
	_expression.checkTypeRequirements();
	if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType))
		BOOST_THROW_EXCEPTION(_expression.createTypeError("Type not implicitly convertible to expected type."));
	//@todo provide more information to the exception
}

void Block::checkTypeRequirements()
{
	for (shared_ptr<Statement> const& statement: m_statements)
		statement->checkTypeRequirements();
}

void IfStatement::checkTypeRequirements()
{
	expectType(*m_condition, BoolType());
	m_trueBody->checkTypeRequirements();
	if (m_falseBody)
		m_falseBody->checkTypeRequirements();
}

void WhileStatement::checkTypeRequirements()
{
	expectType(*m_condition, BoolType());
	m_body->checkTypeRequirements();
}

void Continue::checkTypeRequirements()
{
}

void Break::checkTypeRequirements()
{
}

void Return::checkTypeRequirements()
{
	assert(m_returnParameters);
	if (m_returnParameters->getParameters().size() != 1)
		BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
											  "than in returns declaration."));
	// this could later be changed such that the paramaters type is an anonymous struct type,
	// but for now, we only allow one return parameter
	expectType(*m_expression, *m_returnParameters->getParameters().front()->getType());
}

void VariableDefinition::checkTypeRequirements()
{
	// Variables can be declared without type (with "var"), in which case the first assignment
	// setsthe type.
	// Note that assignments before the first declaration are legal because of the special scoping
	// rules inherited from JavaScript.
	if (m_value)
	{
		if (m_variable->getType())
			expectType(*m_value, *m_variable->getType());
		else
		{
			// no type declared and no previous assignment, infer the type
			m_value->checkTypeRequirements();
			m_variable->setType(m_value->getType());
		}
	}
}

void Assignment::checkTypeRequirements()
{
	//@todo lefthandside actually has to be assignable
	// add a feature to the type system to check that
	m_leftHandSide->checkTypeRequirements();
	if (!m_leftHandSide->isLvalue())
		BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
	expectType(*m_rightHandSide, *m_leftHandSide->getType());
	m_type = m_leftHandSide->getType();
	if (m_assigmentOperator != Token::ASSIGN)
	{
		// compound assignment
		if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator)))
			BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
	}
}

void UnaryOperation::checkTypeRequirements()
{
	// INC, DEC, ADD, SUB, NOT, BIT_NOT, DELETE
	m_subExpression->checkTypeRequirements();
	if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE)
	{
		if (!m_subExpression->isLvalue())
			BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
	}
	m_type = m_subExpression->getType();
	if (!m_type->acceptsUnaryOperator(m_operator))
		BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type."));
}

void BinaryOperation::checkTypeRequirements()
{
	m_right->checkTypeRequirements();
	m_left->checkTypeRequirements();
	if (m_right->getType()->isImplicitlyConvertibleTo(*m_left->getType()))
		m_commonType = m_left->getType();
	else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType()))
		m_commonType = m_right->getType();
	else
		BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation."));
	if (Token::isCompareOp(m_operator))
		m_type = make_shared<BoolType>();
	else
	{
		assert(Token::isBinaryOp(m_operator));
		m_type = m_commonType;
		if (!m_commonType->acceptsBinaryOperator(m_operator))
			BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
	}
}

void FunctionCall::checkTypeRequirements()
{
	m_expression->checkTypeRequirements();
	for (ASTPointer<Expression> const& argument: m_arguments)
		argument->checkTypeRequirements();

	Type const* expressionType = m_expression->getType().get();
	if (isTypeConversion())
	{
		TypeType const* type = dynamic_cast<TypeType const*>(expressionType);
		assert(type);
		//@todo for structs, we have to check the number of arguments to be equal to the
		// number of non-mapping members
		if (m_arguments.size() != 1)
			BOOST_THROW_EXCEPTION(createTypeError("More than one argument for "
														   "explicit type conersion."));
		if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType()))
			BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
		m_type = type->getActualType();
	}
	else
	{
		//@todo would be nice to create a struct type from the arguments
		// and then ask if that is implicitly convertible to the struct represented by the
		// function parameters
		FunctionType const* function = dynamic_cast<FunctionType const*>(expressionType);
		assert(function);
		FunctionDefinition const& fun = function->getFunction();
		vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters();
		if (parameters.size() != m_arguments.size())
			BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
		for (size_t i = 0; i < m_arguments.size(); ++i)
			if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType()))
				BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
		// @todo actually the return type should be an anonymous struct,
		// but we change it to the type of the first return value until we have structs
		if (fun.getReturnParameterList()->getParameters().empty())
			m_type = make_shared<VoidType>();
		else
			m_type = fun.getReturnParameterList()->getParameters().front()->getType();
	}
}

bool FunctionCall::isTypeConversion() const
{
	return m_expression->getType()->getCategory() == Type::Category::TYPE;
}

void MemberAccess::checkTypeRequirements()
{
	assert(false); // not yet implemented
	// m_type = ;
}

void IndexAccess::checkTypeRequirements()
{
	assert(false); // not yet implemented
	// m_type = ;
}

void Identifier::checkTypeRequirements()
{
	assert(m_referencedDeclaration);
	//@todo these dynamic casts here are not really nice...
	// is i useful to have an AST visitor here?
	// or can this already be done in NameAndTypeResolver?
	// the only problem we get there is that in
	// var x;
	// x = 2;
	// var y = x;
	// the type of x is not yet determined.
	VariableDeclaration* variable = dynamic_cast<VariableDeclaration*>(m_referencedDeclaration);
	if (variable)
	{
		if (!variable->getType())
			BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
		m_type = variable->getType();
		m_isLvalue = true;
		return;
	}
	//@todo can we unify these with TypeName::toType()?
	StructDefinition* structDef = dynamic_cast<StructDefinition*>(m_referencedDeclaration);
	if (structDef)
	{
		// note that we do not have a struct type here
		m_type = make_shared<TypeType>(make_shared<StructType>(*structDef));
		return;
	}
	FunctionDefinition* functionDef = dynamic_cast<FunctionDefinition*>(m_referencedDeclaration);
	if (functionDef)
	{
		// a function reference is not a TypeType, because calling a TypeType converts to the type.
		// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
		// conversion.
		m_type = make_shared<FunctionType>(*functionDef);
		return;
	}
	ContractDefinition* contractDef = dynamic_cast<ContractDefinition*>(m_referencedDeclaration);
	if (contractDef)
	{
		m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef));
		return;
	}
	assert(false); // declaration reference of unknown/forbidden type
}

void ElementaryTypeNameExpression::checkTypeRequirements()
{
	m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
}

void Literal::checkTypeRequirements()
{
	m_type = Type::forLiteral(*this);
}

}
}
<commit_msg>Bugfix: Allow empty return statements without type checking.<commit_after>/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Solidity abstract syntax tree.
 */

#include <algorithm>

#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/Exceptions.h>

using namespace std;

namespace dev
{
namespace solidity
{

void ContractDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		listAccept(m_definedStructs, _visitor);
		listAccept(m_stateVariables, _visitor);
		listAccept(m_definedFunctions, _visitor);
	}
	_visitor.endVisit(*this);
}

void StructDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		listAccept(m_members, _visitor);
	_visitor.endVisit(*this);
}

void ParameterList::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		listAccept(m_parameters, _visitor);
	_visitor.endVisit(*this);
}

void FunctionDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_parameters->accept(_visitor);
		if (m_returnParameters)
			m_returnParameters->accept(_visitor);
		m_body->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void VariableDeclaration::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		if (m_typeName)
			m_typeName->accept(_visitor);
	_visitor.endVisit(*this);
}

void TypeName::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void ElementaryTypeName::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void UserDefinedTypeName::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Mapping::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_keyType->accept(_visitor);
		m_valueType->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Statement::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Block::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		listAccept(m_statements, _visitor);
	_visitor.endVisit(*this);
}

void IfStatement::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_condition->accept(_visitor);
		m_trueBody->accept(_visitor);
		if (m_falseBody)
			m_falseBody->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void BreakableStatement::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void WhileStatement::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_condition->accept(_visitor);
		m_body->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Continue::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Break::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Return::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		if (m_expression)
			m_expression->accept(_visitor);
	_visitor.endVisit(*this);
}

void VariableDefinition::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_variable->accept(_visitor);
		if (m_value)
			m_value->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Assignment::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_leftHandSide->accept(_visitor);
		m_rightHandSide->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void UnaryOperation::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		m_subExpression->accept(_visitor);
	_visitor.endVisit(*this);
}

void BinaryOperation::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_left->accept(_visitor);
		m_right->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void FunctionCall::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_expression->accept(_visitor);
		listAccept(m_arguments, _visitor);
	}
	_visitor.endVisit(*this);
}

void MemberAccess::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
		m_expression->accept(_visitor);
	_visitor.endVisit(*this);
}

void IndexAccess::accept(ASTVisitor& _visitor)
{
	if (_visitor.visit(*this))
	{
		m_base->accept(_visitor);
		m_index->accept(_visitor);
	}
	_visitor.endVisit(*this);
}

void Identifier::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

void Literal::accept(ASTVisitor& _visitor)
{
	_visitor.visit(*this);
	_visitor.endVisit(*this);
}

TypeError ASTNode::createTypeError(string const& _description)
{
	return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
}

void Statement::expectType(Expression& _expression, const Type& _expectedType)
{
	_expression.checkTypeRequirements();
	if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType))
		BOOST_THROW_EXCEPTION(_expression.createTypeError("Type not implicitly convertible to expected type."));
	//@todo provide more information to the exception
}

void Block::checkTypeRequirements()
{
	for (shared_ptr<Statement> const& statement: m_statements)
		statement->checkTypeRequirements();
}

void IfStatement::checkTypeRequirements()
{
	expectType(*m_condition, BoolType());
	m_trueBody->checkTypeRequirements();
	if (m_falseBody)
		m_falseBody->checkTypeRequirements();
}

void WhileStatement::checkTypeRequirements()
{
	expectType(*m_condition, BoolType());
	m_body->checkTypeRequirements();
}

void Continue::checkTypeRequirements()
{
}

void Break::checkTypeRequirements()
{
}

void Return::checkTypeRequirements()
{
	assert(m_returnParameters);
	if (!m_expression)
		return;
	if (m_returnParameters->getParameters().size() != 1)
		BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
											  "than in returns declaration."));
	// this could later be changed such that the paramaters type is an anonymous struct type,
	// but for now, we only allow one return parameter
	expectType(*m_expression, *m_returnParameters->getParameters().front()->getType());
}

void VariableDefinition::checkTypeRequirements()
{
	// Variables can be declared without type (with "var"), in which case the first assignment
	// setsthe type.
	// Note that assignments before the first declaration are legal because of the special scoping
	// rules inherited from JavaScript.
	if (m_value)
	{
		if (m_variable->getType())
			expectType(*m_value, *m_variable->getType());
		else
		{
			// no type declared and no previous assignment, infer the type
			m_value->checkTypeRequirements();
			m_variable->setType(m_value->getType());
		}
	}
}

void Assignment::checkTypeRequirements()
{
	//@todo lefthandside actually has to be assignable
	// add a feature to the type system to check that
	m_leftHandSide->checkTypeRequirements();
	if (!m_leftHandSide->isLvalue())
		BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
	expectType(*m_rightHandSide, *m_leftHandSide->getType());
	m_type = m_leftHandSide->getType();
	if (m_assigmentOperator != Token::ASSIGN)
	{
		// compound assignment
		if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator)))
			BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
	}
}

void UnaryOperation::checkTypeRequirements()
{
	// INC, DEC, ADD, SUB, NOT, BIT_NOT, DELETE
	m_subExpression->checkTypeRequirements();
	if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE)
	{
		if (!m_subExpression->isLvalue())
			BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
	}
	m_type = m_subExpression->getType();
	if (!m_type->acceptsUnaryOperator(m_operator))
		BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type."));
}

void BinaryOperation::checkTypeRequirements()
{
	m_right->checkTypeRequirements();
	m_left->checkTypeRequirements();
	if (m_right->getType()->isImplicitlyConvertibleTo(*m_left->getType()))
		m_commonType = m_left->getType();
	else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType()))
		m_commonType = m_right->getType();
	else
		BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation."));
	if (Token::isCompareOp(m_operator))
		m_type = make_shared<BoolType>();
	else
	{
		assert(Token::isBinaryOp(m_operator));
		m_type = m_commonType;
		if (!m_commonType->acceptsBinaryOperator(m_operator))
			BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
	}
}

void FunctionCall::checkTypeRequirements()
{
	m_expression->checkTypeRequirements();
	for (ASTPointer<Expression> const& argument: m_arguments)
		argument->checkTypeRequirements();

	Type const* expressionType = m_expression->getType().get();
	if (isTypeConversion())
	{
		TypeType const* type = dynamic_cast<TypeType const*>(expressionType);
		assert(type);
		//@todo for structs, we have to check the number of arguments to be equal to the
		// number of non-mapping members
		if (m_arguments.size() != 1)
			BOOST_THROW_EXCEPTION(createTypeError("More than one argument for "
														   "explicit type conersion."));
		if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType()))
			BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
		m_type = type->getActualType();
	}
	else
	{
		//@todo would be nice to create a struct type from the arguments
		// and then ask if that is implicitly convertible to the struct represented by the
		// function parameters
		FunctionType const* function = dynamic_cast<FunctionType const*>(expressionType);
		assert(function);
		FunctionDefinition const& fun = function->getFunction();
		vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters();
		if (parameters.size() != m_arguments.size())
			BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
		for (size_t i = 0; i < m_arguments.size(); ++i)
			if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType()))
				BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
		// @todo actually the return type should be an anonymous struct,
		// but we change it to the type of the first return value until we have structs
		if (fun.getReturnParameterList()->getParameters().empty())
			m_type = make_shared<VoidType>();
		else
			m_type = fun.getReturnParameterList()->getParameters().front()->getType();
	}
}

bool FunctionCall::isTypeConversion() const
{
	return m_expression->getType()->getCategory() == Type::Category::TYPE;
}

void MemberAccess::checkTypeRequirements()
{
	assert(false); // not yet implemented
	// m_type = ;
}

void IndexAccess::checkTypeRequirements()
{
	assert(false); // not yet implemented
	// m_type = ;
}

void Identifier::checkTypeRequirements()
{
	assert(m_referencedDeclaration);
	//@todo these dynamic casts here are not really nice...
	// is i useful to have an AST visitor here?
	// or can this already be done in NameAndTypeResolver?
	// the only problem we get there is that in
	// var x;
	// x = 2;
	// var y = x;
	// the type of x is not yet determined.
	VariableDeclaration* variable = dynamic_cast<VariableDeclaration*>(m_referencedDeclaration);
	if (variable)
	{
		if (!variable->getType())
			BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
		m_type = variable->getType();
		m_isLvalue = true;
		return;
	}
	//@todo can we unify these with TypeName::toType()?
	StructDefinition* structDef = dynamic_cast<StructDefinition*>(m_referencedDeclaration);
	if (structDef)
	{
		// note that we do not have a struct type here
		m_type = make_shared<TypeType>(make_shared<StructType>(*structDef));
		return;
	}
	FunctionDefinition* functionDef = dynamic_cast<FunctionDefinition*>(m_referencedDeclaration);
	if (functionDef)
	{
		// a function reference is not a TypeType, because calling a TypeType converts to the type.
		// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
		// conversion.
		m_type = make_shared<FunctionType>(*functionDef);
		return;
	}
	ContractDefinition* contractDef = dynamic_cast<ContractDefinition*>(m_referencedDeclaration);
	if (contractDef)
	{
		m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef));
		return;
	}
	assert(false); // declaration reference of unknown/forbidden type
}

void ElementaryTypeNameExpression::checkTypeRequirements()
{
	m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
}

void Literal::checkTypeRequirements()
{
	m_type = Type::forLiteral(*this);
}

}
}
<|endoftext|>